<template>
  <div class="javascript-demo">
    <h2 class="section-title">JavaScript 特性演示</h2>
    
    <div class="demo-grid">
      <!-- ES6+ 新特性 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>ES6+ 新特性</h3>
          <button class="code-toggle" @click="toggleCode('es6')">
            {{ showCode.es6 ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.es6">
            <pre class="code-viewer"><code>// 变量声明
let count = 0;
const PI = 3.14159;

// 箭头函数
const add = (a, b) => a + b;

// 模板字符串
const name = 'World';
const greeting = `Hello ${name}!`;

// 解构赋值
const { title, content } = { title: '标题', content: '内容' };
const [first, second] = [1, 2, 3];

// 展开运算符
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];

// 可选链操作符
const user = { name: 'John', address: { city: 'New York' } };
const city = user?.address?.city;

// 空值合并操作符
const value = null ?? '默认值';

// BigInt
const bigNumber = 9007199254740991n;
const result = bigNumber + 1n;

// Promise.allSettled
const promises = [
  Promise.resolve(1),
  Promise.reject('错误'),
  Promise.resolve(3)
];
Promise.allSettled(promises).then(results => {
  console.log(results);
});

// globalThis
const globalObj = globalThis;
console.log(globalObj === window); // 在浏览器中为 true</code></pre>
          </div>
          <div class="demo-preview">
            <div class="feature-list">
              <div class="feature-item">
                <span class="feature-label">变量声明:</span>
                <span class="feature-value">{{ es6Demo.variables }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">箭头函数:</span>
                <span class="feature-value">{{ es6Demo.arrowFunction }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">模板字符串:</span>
                <span class="feature-value">{{ es6Demo.templateString }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">解构赋值:</span>
                <span class="feature-value">{{ es6Demo.destructuring }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">展开运算符:</span>
                <span class="feature-value">{{ es6Demo.spread }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">可选链:</span>
                <span class="feature-value">{{ es6Demo.optionalChaining }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">空值合并:</span>
                <span class="feature-value">{{ es6Demo.nullishCoalescing }}</span>
              </div>
              <div class="feature-item">
                <span class="feature-label">BigInt:</span>
                <span class="feature-value">{{ es6Demo.bigInt }}</span>
              </div>
            </div>
            <div class="interactive-demo">
              <div class="input-group">
                <input v-model="es6Demo.input" placeholder="输入文本">
                <button @click="es6Demo.processInput">处理</button>
              </div>
              <div class="result-display" v-if="es6Demo.result">
                {{ es6Demo.result }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 数组操作 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>数组操作</h3>
          <button class="code-toggle" @click="toggleCode('array')">
            {{ showCode.array ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.array">
            <pre class="code-viewer"><code>// 数组方法
const numbers = [1, 2, 3, 4, 5];

// Map
const doubled = numbers.map(x => x * 2);

// Filter
const evenNumbers = numbers.filter(x => x % 2 === 0);

// Reduce
const sum = numbers.reduce((acc, cur) => acc + cur, 0);

// Find
const found = numbers.find(x => x > 3);

// Some/Every
const hasEven = numbers.some(x => x % 2 === 0);
const allPositive = numbers.every(x => x > 0);

// Flat
const nested = [1, [2, 3], [4, [5, 6]]];
const flattened = nested.flat(2);

// Array.from
const arrayLike = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
const array = Array.from(arrayLike);</code></pre>
          </div>
          <div class="demo-preview">
            <div class="array-demo">
              <div class="array-controls">
                <input v-model="arrayDemo.newItem" placeholder="添加数字" @keyup.enter="addToArray">
                <button @click="addToArray">添加</button>
                <button @click="arrayDemo.original = []">清空</button>
              </div>
              <div class="array-display">
                原数组: [{{ arrayDemo.original.join(', ') }}]
              </div>
              <div class="array-results">
                <div class="result-item">
                  <span class="result-label">Map (×2):</span>
                  <span class="result-value">[{{ arrayDemo.mapped.join(', ') }}]</span>
                </div>
                <div class="result-item">
                  <span class="result-label">Filter (偶数):</span>
                  <span class="result-value">[{{ arrayDemo.filtered.join(', ') }}]</span>
                </div>
                <div class="result-item">
                  <span class="result-label">Reduce (求和):</span>
                  <span class="result-value">{{ arrayDemo.reduced }}</span>
                </div>
                <div class="result-item">
                  <span class="result-label">Find (>3):</span>
                  <span class="result-value">{{ arrayDemo.found }}</span>
                </div>
                <div class="result-item">
                  <span class="result-label">Flat:</span>
                  <span class="result-value">[{{ arrayDemo.flattened.join(', ') }}]</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 异步编程 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>异步编程</h3>
          <button class="code-toggle" @click="toggleCode('async')">
            {{ showCode.async ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.async">
            <pre class="code-viewer"><code>// Promise
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('数据获取成功');
    }, 1000);
  });
};

// Async/Await
const getData = async () => {
  try {
    const result = await fetchData();
    return result;
  } catch (error) {
    throw new Error('获取失败');
  }
};

// Promise.all
const fetchMultiple = async () => {
  const results = await Promise.all([
    fetchData(),
    fetchData(),
    fetchData()
  ]);
  return results;
};

// Promise.race
const fetchWithTimeout = async () => {
  const timeout = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('超时')), 2000)
  );
  return Promise.race([fetchData(), timeout]);
};

// Promise.allSettled
const fetchWithSettled = async () => {
  const results = await Promise.allSettled([
    fetchData(),
    Promise.reject('请求失败'),
    fetchData()
  ]);
  return results;
};

// Generator
function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}</code></pre>
          </div>
          <div class="demo-preview">
            <div class="async-demo">
              <div class="status-box" :class="asyncDemo.status">
                状态: {{ asyncDemo.status }}
              </div>
              <div class="progress-bar" v-if="asyncDemo.status === 'running'">
                <div class="progress" :style="{ width: asyncDemo.progress + '%' }"></div>
              </div>
              <div class="controls">
                <button @click="runAsyncDemo('single')" :disabled="asyncDemo.status === 'running'">单个请求</button>
                <button @click="runAsyncDemo('multiple')" :disabled="asyncDemo.status === 'running'">多个请求</button>
                <button @click="runAsyncDemo('race')" :disabled="asyncDemo.status === 'running'">竞态请求</button>
                <button @click="runAsyncDemo('settled')" :disabled="asyncDemo.status === 'running'">全部完成</button>
                <button @click="runAsyncDemo('generator')" :disabled="asyncDemo.status === 'running'">生成器</button>
              </div>
              <div class="result-box" v-if="asyncDemo.result">
                结果: {{ asyncDemo.result }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 面向对象 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>面向对象</h3>
          <button class="code-toggle" @click="toggleCode('oop')">
            {{ showCode.oop ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.oop">
            <pre class="code-viewer"><code>// 类定义
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    return `你好，我是${this.name}`;
  }

  get info() {
    return `${this.name}, ${this.age}岁`;
  }
}

// 继承
class Student extends Person {
  constructor(name, age, grade) {
    super(name, age);
    this.grade = grade;
  }

  study() {
    return `${this.name}正在学习`;
  }
}

// 私有字段
class BankAccount {
  #balance = 0;
  
  deposit(amount) {
    this.#balance += amount;
  }
  
  getBalance() {
    return this.#balance;
  }
}

// 静态方法
class MathUtils {
  static add(a, b) {
    return a + b;
  }
}</code></pre>
          </div>
          <div class="demo-preview">
            <div class="oop-demo">
              <div class="object-display">
                <div class="object-info">
                  <p>姓名: {{ oopDemo.person.name }}</p>
                  <p>年龄: {{ oopDemo.person.age }}</p>
                  <p>信息: {{ oopDemo.person.info }}</p>
                  <p>余额: {{ oopDemo.account.getBalance() }}</p>
                  <p v-if="oopDemo.greeting" class="result-text">{{ oopDemo.greeting }}</p>
                  <p v-if="oopDemo.studyResult" class="result-text">{{ oopDemo.studyResult }}</p>
                  <p v-if="oopDemo.message" class="result-text">{{ oopDemo.message }}</p>
                </div>
                <div class="object-actions">
                  <button @click="sayHello">打招呼</button>
                  <button @click="study">学习</button>
                  <button @click="deposit(100)">存款</button>
                </div>
              </div>
              <div class="object-creation">
                <h4>创建新对象</h4>
                <div class="input-group">
                  <input v-model="oopDemo.newName" placeholder="姓名">
                  <input v-model="oopDemo.newAge" placeholder="年龄" type="number">
                  <button @click="createNewPerson">创建</button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 函数式编程 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>函数式编程</h3>
          <button class="code-toggle" @click="toggleCode('functional')">
            {{ showCode.functional ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.functional">
            <pre class="code-viewer"><code>// 高阶函数
const compose = (...fns) => x => 
  fns.reduceRight((v, f) => f(v), x);

// 柯里化
const curry = (fn) => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    }
    return (...moreArgs) => 
      curried.apply(this, args.concat(moreArgs));
  };
};

// 纯函数
const add = (a, b) => a + b;

// 不可变数据
const updateUser = (user, updates) => ({
  ...user,
  ...updates
});

// 函数组合
const double = x => x * 2;
const addOne = x => x + 1;
const composed = compose(double, addOne);</code></pre>
          </div>
          <div class="demo-preview">
            <div class="functional-demo">
              <div class="function-display">
                <div class="function-info">
                  <p>纯函数结果: {{ functionalDemo.pureResult }}</p>
                  <p>柯里化结果: {{ functionalDemo.curryResult }}</p>
                  <p>组合函数结果: {{ functionalDemo.composeResult }}</p>
                  <p v-if="functionalDemo.customResult" class="result-text">自定义计算结果: {{ functionalDemo.customResult }}</p>
                </div>
                <div class="function-actions">
                  <button @click="runFunctionalDemo('pure')">纯函数</button>
                  <button @click="runFunctionalDemo('curry')">柯里化</button>
                  <button @click="runFunctionalDemo('compose')">组合</button>
                </div>
              </div>
              <div class="function-input">
                <input v-model="functionalDemo.input" placeholder="输入数字" type="number">
                <button @click="runFunctionalDemo('custom')">自定义计算</button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 模块化 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>模块化</h3>
          <button class="code-toggle" @click="toggleCode('module')">
            {{ showCode.module ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.module">
            <pre class="code-viewer"><code>// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

// utils.js
export const formatDate = (date) => {
  return new Date(date).toLocaleDateString();
};

// constants.js
export const PI = 3.14159;
export const MAX_USERS = 100;

// main.js
import { add, subtract } from './math';
import { formatDate } from './utils';
import { PI, MAX_USERS } from './constants';

// 动态导入
const loadModule = async () => {
  const module = await import('./dynamic-module');
  return module.default();
};</code></pre>
          </div>
          <div class="demo-preview">
            <div class="module-demo">
              <div class="module-info">
                <p>模块化示例展示了如何：</p>
                <ul>
                  <li>导出函数和变量</li>
                  <li>导入模块</li>
                  <li>使用模块化组织代码</li>
                  <li>动态导入模块</li>
                </ul>
              </div>
              <div class="module-actions">
                <button @click="loadDynamicModule">加载动态模块</button>
              </div>
              <div class="module-result" v-if="moduleDemo.result">
                {{ moduleDemo.result }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 错误处理 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>错误处理</h3>
          <button class="code-toggle" @click="toggleCode('error')">
            {{ showCode.error ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.error">
            <pre class="code-viewer"><code>// try-catch
try {
  throw new Error('测试错误');
} catch (error) {
  console.error('捕获到错误:', error.message);
} finally {
  console.log('清理工作');
}

// 自定义错误
class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
  }
}

// Promise 错误处理
Promise.reject(new Error('Promise错误'))
  .catch(error => {
    console.error('Promise错误:', error.message);
  });

// 全局错误处理
window.onerror = (message, source, lineno, colno, error) => {
  console.error('全局错误:', error);
};

// 未捕获的Promise错误
window.onunhandledrejection = (event) => {
  console.error('未处理的Promise错误:', event.reason);
};</code></pre>
          </div>
          <div class="demo-preview">
            <div class="error-demo">
              <div class="controls">
                <button @click="triggerError('standard')">标准错误</button>
                <button @click="triggerError('custom')">自定义错误</button>
                <button @click="triggerError('promise')">Promise错误</button>
                <button @click="triggerError('async')">异步错误</button>
              </div>
              <div class="error-display" v-if="errorDemo.message">
                {{ errorDemo.message }}
              </div>
              <div class="error-stack" v-if="errorDemo.stack">
                <pre>{{ errorDemo.stack }}</pre>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 正则表达式 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>正则表达式</h3>
          <button class="code-toggle" @click="toggleCode('regex')">
            {{ showCode.regex ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.regex">
            <pre class="code-viewer"><code>// 基本匹配
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex = /^1[3-9]\d{9}$/;

// 正则方法
const str = 'Hello World';
str.match(/o/g);  // ['o', 'o']
str.replace(/o/g, '0');  // 'Hell0 W0rld'

// 正则标志
const regex = /pattern/gimsy;

// 正则表达式示例
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2024-03-15'.match(dateRegex);
const [_, year, month, day] = match;</code></pre>
          </div>
          <div class="demo-preview">
            <div class="regex-demo">
              <div class="regex-input">
                <input 
                  v-model="regexDemo.input" 
                  placeholder="输入文本"
                  @input="testRegex"
                >
                <select v-model="regexDemo.pattern" @change="testRegex">
                  <option value="email">邮箱</option>
                  <option value="phone">手机号</option>
                  <option value="date">日期</option>
                  <option value="custom">自定义</option>
                </select>
              </div>
              <div class="regex-custom" v-if="regexDemo.pattern === 'custom'">
                <input 
                  v-model="regexDemo.customPattern" 
                  placeholder="输入正则表达式"
                  @input="testCustomRegex"
                >
              </div>
              <div class="regex-result" :class="{ valid: regexDemo.isValid }">
                {{ regexDemo.isValid ? '匹配成功' : '匹配失败' }}
              </div>
              <div class="regex-matches" v-if="regexDemo.matches.length > 0">
                <h4>匹配结果:</h4>
                <ul>
                  <li v-for="(match, index) in regexDemo.matches" :key="index">
                    {{ match }}
                  </li>
                </ul>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- WebRTC -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>WebRTC</h3>
          <button class="code-toggle" @click="toggleCode('webrtc')">
            {{ showCode.webrtc ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.webrtc">
            <pre class="code-viewer"><code>// 获取媒体流
const stream = await navigator.mediaDevices.getUserMedia({
  video: true,
  audio: true
});

// 创建 RTCPeerConnection
const peerConnection = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' }
  ]
});

// 添加媒体轨道
stream.getTracks().forEach(track => {
  peerConnection.addTrack(track, stream);
});

// 创建并发送提议
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

// 处理 ICE 候选
peerConnection.onicecandidate = event => {
  if (event.candidate) {
    // 发送候选到对等端
  }
};

// 数据通道
const dataChannel = peerConnection.createDataChannel('chat');
dataChannel.onmessage = event => {
  console.log('收到消息:', event.data);
};</code></pre>
          </div>
          <div class="demo-preview">
            <div class="webrtc-demo">
              <div class="demo-description">
                <p>这个示例展示了 WebRTC 的主要功能：</p>
                <ul>
                  <li>视频通话</li>
                  <li>屏幕共享</li>
                  <li>数据传输</li>
                </ul>
              </div>
              <div class="media-controls">
                <div class="video-container">
                  <video ref="localVideo" autoplay muted playsinline></video>
                  <video ref="remoteVideo" autoplay playsinline></video>
                </div>
                <div class="control-buttons">
                  <button @click="startVideo" :disabled="webrtcDemo.isVideoActive">
                    开启视频
                  </button>
                  <button @click="stopVideo" :disabled="!webrtcDemo.isVideoActive">
                    关闭视频
                  </button>
                  <button @click="startScreenShare" :disabled="webrtcDemo.isScreenSharing">
                    屏幕共享
                  </button>
                  <button @click="stopScreenShare" :disabled="!webrtcDemo.isScreenSharing">
                    停止共享
                  </button>
                </div>
              </div>
              <div class="data-channel" v-if="webrtcDemo.isConnected">
                <div class="chat-box">
                  <div class="messages" ref="messages">
                    <div v-for="(msg, index) in webrtcDemo.messages" 
                         :key="index" 
                         :class="['message', msg.type]">
                      {{ msg.text }}
                    </div>
                  </div>
                  <div class="input-area">
                    <input v-model="webrtcDemo.messageInput" 
                           @keyup.enter="sendMessage"
                           placeholder="输入消息...">
                    <button @click="sendMessage">发送</button>
                  </div>
                </div>
              </div>
              <div class="connection-status" :class="webrtcDemo.connectionStatus">
                {{ webrtcDemo.statusMessage }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- WebSocket 实时通信 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>WebSocket 实时通信</h3>
          <button class="code-toggle" @click="toggleCode('websocket')">
            {{ showCode.websocket ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.websocket">
            <pre class="code-viewer"><code>// 创建WebSocket连接
const socket = new WebSocket('wss://echo.websocket.org');

// 连接打开时
socket.onopen = () => {
  console.log('连接已建立');
};

// 接收消息
socket.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

// 发送消息
socket.send('Hello Server!');

// 连接关闭时
socket.onclose = () => {
  console.log('连接已关闭');
};

// 发生错误时
socket.onerror = (error) => {
  console.error('WebSocket错误:', error);
};

// 心跳检测
setInterval(() => {
  if (socket.readyState === WebSocket.OPEN) {
    socket.send('ping');
  }
}, 30000);</code></pre>
          </div>
          <div class="demo-preview">
            <div class="websocket-demo">
              <div class="connection-status" :class="websocketDemo.status">
                {{ websocketDemo.statusMessage }}
              </div>
              <div class="chat-container">
                <div class="messages" ref="wsMessages">
                  <div v-for="(msg, index) in websocketDemo.messages" 
                       :key="index" 
                       :class="['message', msg.type]">
                    {{ msg.text }}
                  </div>
                </div>
                <div class="input-area">
                  <input v-model="websocketDemo.messageInput" 
                         @keyup.enter="sendWebSocketMessage"
                         placeholder="输入消息...">
                  <button @click="sendWebSocketMessage">发送</button>
                </div>
              </div>
              <div class="controls">
                <button @click="connectWebSocket" :disabled="websocketDemo.isConnected">
                  连接
                </button>
                <button @click="disconnectWebSocket" :disabled="!websocketDemo.isConnected">
                  断开
                </button>
                <button @click="sendPing" :disabled="!websocketDemo.isConnected">
                  发送Ping
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Canvas 动画与交互 -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Canvas 动画与交互</h3>
          <button class="code-toggle" @click="toggleCode('canvas')">
            {{ showCode.canvas ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.canvas">
            <pre class="code-viewer"><code>// 获取Canvas上下文
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 设置画布尺寸
canvas.width = 500;
canvas.height = 300;

// 绘制形状
ctx.fillStyle = 'rgba(0, 255, 136, 0.5)';
ctx.fillRect(50, 50, 100, 100);

ctx.beginPath();
ctx.arc(250, 150, 50, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(0, 149, 255, 0.5)';
ctx.fill();

// 动画循环
function animate() {
  // 清除画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 更新对象位置
  x += dx;
  y += dy;
  
  // 边界检测
  if (x + radius > canvas.width || x - radius < 0) {
    dx = -dx;
  }
  if (y + radius > canvas.height || y - radius < 0) {
    dy = -dy;
  }
  
  // 绘制对象
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI * 2);
  ctx.fillStyle = color;
  ctx.fill();
  
  // 请求下一帧
  requestAnimationFrame(animate);
}

// 开始动画
animate();

// 交互处理
canvas.addEventListener('mousemove', (event) => {
  const rect = canvas.getBoundingClientRect();
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;
  
  // 根据鼠标位置更新对象
  // ...
});</code></pre>
          </div>
          <div class="demo-preview">
            <div class="canvas-demo">
              <canvas ref="canvas" width="500" height="300"></canvas>
              <div class="canvas-controls">
                <div class="control-group">
                  <label>形状:</label>
                  <select v-model="canvasDemo.shape">
                    <option value="circle">圆形</option>
                    <option value="square">方形</option>
                    <option value="triangle">三角形</option>
                  </select>
                </div>
                <div class="control-group">
                  <label>颜色:</label>
                  <input type="color" v-model="canvasDemo.color">
                </div>
                <div class="control-group">
                  <label>速度:</label>
                  <input type="range" v-model="canvasDemo.speed" min="1" max="10">
                </div>
                <div class="control-group">
                  <label>数量:</label>
                  <input type="range" v-model="canvasDemo.count" min="1" max="20">
                </div>
                <button @click="toggleCanvasAnimation">
                  {{ canvasDemo.isAnimating ? '停止' : '开始' }}动画
                </button>
                <button @click="clearCanvas">清除</button>
              </div>
              <div class="canvas-interaction">
                <p>提示: 点击画布添加对象，拖动对象改变位置</p>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Bluetooth API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Bluetooth API</h3>
          <button class="code-toggle" @click="toggleCode('bluetooth')">
            {{ showCode.bluetooth ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.bluetooth">
            <pre class="code-viewer"><code>// 请求蓝牙设备
navigator.bluetooth.requestDevice({
  // 接受所有设备
  acceptAllDevices: true,
  // 或者使用过滤器
  filters: [
    { services: ['heart_rate'] },
    { namePrefix: 'MyDevice' }
  ],
  // 可选服务
  optionalServices: ['battery_service']
})
.then(device => {
  console.log('设备已选择:', device.name);
  return device.gatt.connect();
})
.then(server => {
  console.log('GATT服务器已连接');
  return server.getPrimaryService('heart_rate');
})
.then(service => {
  return service.getCharacteristic('heart_rate_measurement');
})
.then(characteristic => {
  return characteristic.startNotifications();
})
.then(characteristic => {
  characteristic.addEventListener('characteristicvaluechanged', handleCharacteristicValueChanged);
})
.catch(error => {
  console.error('蓝牙错误:', error);
});

// 处理特征值变化
function handleCharacteristicValueChanged(event) {
  const value = event.target.value;
  const heartRate = value.getUint8(1);
  console.log('心率:', heartRate);
}

// 断开连接
function disconnect() {
  if (device.gatt.connected) {
    device.gatt.disconnect();
  }
}</code></pre>
          </div>
          <div class="demo-preview">
            <div class="bluetooth-demo">
              <div class="connection-status" :class="bluetoothDemo.status">
                {{ bluetoothDemo.statusMessage }}
              </div>
              <div class="device-info" v-if="bluetoothDemo.device">
                <h4>设备信息</h4>
                <p>名称: {{ bluetoothDemo.device.name }}</p>
                <p>ID: {{ bluetoothDemo.device.id }}</p>
                <p>已连接: {{ bluetoothDemo.isConnected ? '是' : '否' }}</p>
              </div>
              <div class="service-info" v-if="bluetoothDemo.services.length > 0">
                <h4>可用服务</h4>
                <ul>
                  <li v-for="(service, index) in bluetoothDemo.services" :key="index">
                    {{ service }}
                  </li>
                </ul>
              </div>
              <div class="data-display" v-if="bluetoothDemo.data">
                <h4>接收数据</h4>
                <div class="data-value">{{ bluetoothDemo.data }}</div>
              </div>
              <div class="controls">
                <button @click="scanBluetoothDevices" :disabled="bluetoothDemo.isScanning">
                  {{ bluetoothDemo.isScanning ? '扫描中...' : '扫描设备' }}
                </button>
                <button @click="connectToDevice" :disabled="!bluetoothDemo.device || bluetoothDemo.isConnected">
                  连接
                </button>
                <button @click="disconnectDevice" :disabled="!bluetoothDemo.isConnected">
                  断开连接
                </button>
                <button @click="readCharacteristic" :disabled="!bluetoothDemo.isConnected">
                  读取数据
                </button>
              </div>
              <div class="bluetooth-log">
                <h4>操作日志</h4>
                <div class="log-container">
                  <div v-for="(log, index) in bluetoothDemo.logs" :key="index" class="log-entry">
                    {{ log }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Speech API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Speech API</h3>
          <button class="code-toggle" @click="toggleCode('speech')">
            {{ showCode.speech ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.speech">
            <pre class="code-viewer"><code>// 语音识别
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = 'zh-CN';
recognition.continuous = true;
recognition.interimResults = true;

recognition.onstart = () => {
  console.log('语音识别已启动');
};

recognition.onresult = (event) => {
  const transcript = Array.from(event.results)
    .map(result => result[0].transcript)
    .join('');
  console.log('识别结果:', transcript);
};

recognition.onerror = (event) => {
  console.error('语音识别错误:', event.error);
};

recognition.onend = () => {
  console.log('语音识别已结束');
};

// 启动识别
recognition.start();

// 停止识别
recognition.stop();

// 语音合成
const synthesis = window.speechSynthesis;
const utterance = new SpeechSynthesisUtterance('你好，这是语音合成测试');
utterance.lang = 'zh-CN';
utterance.rate = 1.0;
utterance.pitch = 1.0;
utterance.volume = 1.0;

utterance.onstart = () => {
  console.log('语音合成已启动');
};

utterance.onend = () => {
  console.log('语音合成已结束');
};

// 播放语音
synthesis.speak(utterance);

// 暂停语音
synthesis.pause();

// 恢复语音
synthesis.resume();

// 取消语音
synthesis.cancel();</code></pre>
          </div>
          <div class="demo-preview">
            <div class="speech-demo">
              <div class="speech-section">
                <h4>语音识别</h4>
                <div class="recognition-status" :class="speechDemo.recognitionStatus">
                  {{ speechDemo.recognitionStatusMessage }}
                </div>
                <div class="recognition-result">
                  <div class="interim-result" v-if="speechDemo.interimTranscript">
                    {{ speechDemo.interimTranscript }}
                  </div>
                  <div class="final-result" v-if="speechDemo.finalTranscript">
                    {{ speechDemo.finalTranscript }}
                  </div>
                </div>
                <div class="recognition-controls">
                  <button @click="startRecognition" :disabled="speechDemo.isRecognizing">
                    开始识别
                  </button>
                  <button @click="stopRecognition" :disabled="!speechDemo.isRecognizing">
                    停止识别
                  </button>
                  <select v-model="speechDemo.recognitionLang">
                    <option value="zh-CN">中文 (中国)</option>
                    <option value="en-US">英语 (美国)</option>
                    <option value="ja-JP">日语</option>
                    <option value="ko-KR">韩语</option>
                  </select>
                </div>
              </div>
              
              <div class="speech-section">
                <h4>语音合成</h4>
                <div class="synthesis-status" :class="speechDemo.synthesisStatus">
                  {{ speechDemo.synthesisStatusMessage }}
                </div>
                <div class="synthesis-input">
                  <textarea v-model="speechDemo.synthesisText" 
                            placeholder="输入要合成的文本..."
                            rows="3"></textarea>
                </div>
                <div class="synthesis-controls">
                  <button @click="startSynthesis" :disabled="speechDemo.isSynthesizing">
                    开始合成
                  </button>
                  <button @click="pauseSynthesis" :disabled="!speechDemo.isSynthesizing">
                    暂停
                  </button>
                  <button @click="resumeSynthesis" :disabled="!speechDemo.isPaused">
                    继续
                  </button>
                  <button @click="cancelSynthesis" :disabled="!speechDemo.isSynthesizing">
                    取消
                  </button>
                </div>
                <div class="voice-settings">
                  <div class="setting-group">
                    <label>语速:</label>
                    <input type="range" v-model="speechDemo.rate" min="0.5" max="2" step="0.1">
                    <span>{{ speechDemo.rate }}</span>
                  </div>
                  <div class="setting-group">
                    <label>音调:</label>
                    <input type="range" v-model="speechDemo.pitch" min="0.5" max="2" step="0.1">
                    <span>{{ speechDemo.pitch }}</span>
                  </div>
                  <div class="setting-group">
                    <label>音量:</label>
                    <input type="range" v-model="speechDemo.volume" min="0" max="1" step="0.1">
                    <span>{{ speechDemo.volume }}</span>
                  </div>
                  <div class="setting-group">
                    <label>语言:</label>
                    <select v-model="speechDemo.synthesisLang">
                      <option value="zh-CN">中文 (中国)</option>
                      <option value="en-US">英语 (美国)</option>
                      <option value="ja-JP">日语</option>
                      <option value="ko-KR">韩语</option>
                    </select>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Workers API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Workers API</h3>
          <button class="code-toggle" @click="toggleCode('worker')">
            {{ showCode.worker ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.worker">
            <pre class="code-viewer"><code>// 创建 Worker
const worker = new Worker('worker.js');

// 发送消息给 Worker
worker.postMessage({
  type: 'calculate',
  data: [1, 2, 3, 4, 5]
});

// 接收 Worker 消息
worker.onmessage = (event) => {
  console.log('Worker 返回结果:', event.data);
};

// 错误处理
worker.onerror = (error) => {
  console.error('Worker 错误:', error);
};

// 终止 Worker
worker.terminate();

// worker.js
self.onmessage = (event) => {
  const { type, data } = event.data;
  
  if (type === 'calculate') {
    const result = data.reduce((acc, cur) => acc + cur, 0);
    self.postMessage(result);
  }
};</code></pre>
          </div>
          <div class="demo-preview">
            <div class="worker-demo">
              <div class="task-controls">
                <select v-model="workerDemo.taskType">
                  <option value="fibonacci">斐波那契数列</option>
                  <option value="prime">质数计算</option>
                  <option value="sort">数组排序</option>
                </select>
                <input type="number" v-model="workerDemo.input" placeholder="输入数字">
                <button @click="startWorkerTask" :disabled="workerDemo.isRunning">
                  开始计算
                </button>
                <button @click="stopWorkerTask" :disabled="!workerDemo.isRunning">
                  停止计算
                </button>
              </div>
              <div class="task-status" :class="workerDemo.status">
                {{ workerDemo.statusMessage }}
              </div>
              <div class="task-result" v-if="workerDemo.result">
                <h4>计算结果:</h4>
                <pre>{{ workerDemo.result }}</pre>
              </div>
              <div class="performance-comparison">
                <div class="comparison-item">
                  <span>主线程耗时:</span>
                  <span>{{ workerDemo.mainThreadTime }}ms</span>
                </div>
                <div class="comparison-item">
                  <span>Worker线程耗时:</span>
                  <span>{{ workerDemo.workerTime }}ms</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Animation API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Animation API</h3>
          <button class="code-toggle" @click="toggleCode('animation')">
            {{ showCode.animation ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.animation">
            <pre class="code-viewer"><code>// 创建动画
const element = document.querySelector('.animated-element');
const animation = element.animate([
  { transform: 'translateX(0)', opacity: 1 },
  { transform: 'translateX(100px)', opacity: 0.5 },
  { transform: 'translateX(0)', opacity: 1 }
], {
  duration: 1000,
  iterations: Infinity,
  easing: 'ease-in-out'
});

// 控制动画
animation.play();
animation.pause();
animation.cancel();

// 动画事件
animation.onfinish = () => {
  console.log('动画完成');
};

// 关键帧动画
const keyframes = [
  { transform: 'scale(1)', offset: 0 },
  { transform: 'scale(1.2)', offset: 0.5 },
  { transform: 'scale(1)', offset: 1 }
];

// 动画选项
const options = {
  duration: 1000,
  iterations: Infinity,
  direction: 'alternate',
  easing: 'ease-in-out'
};</code></pre>
          </div>
          <div class="demo-preview">
            <div class="animation-demo">
              <div class="animation-container">
                <div class="animated-element" ref="animatedElement"></div>
              </div>
              <div class="animation-controls">
                <div class="control-group">
                  <label>动画类型:</label>
                  <select v-model="animationDemo.type">
                    <option value="bounce">弹跳</option>
                    <option value="rotate">旋转</option>
                    <option value="scale">缩放</option>
                    <option value="color">颜色</option>
                  </select>
                </div>
                <div class="control-group">
                  <label>持续时间:</label>
                  <input type="range" v-model="animationDemo.duration" min="500" max="3000" step="100">
                  <span>{{ animationDemo.duration }}ms</span>
                </div>
                <div class="control-group">
                  <label>迭代次数:</label>
                  <input type="number" v-model="animationDemo.iterations" min="1" max="10">
                </div>
                <div class="animation-buttons">
                  <button @click="startAnimation" :disabled="animationDemo.isPlaying">
                    开始动画
                  </button>
                  <button @click="stopAnimation" :disabled="!animationDemo.isPlaying">
                    停止动画
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Share API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Share API</h3>
          <button class="code-toggle" @click="toggleCode('share')">
            {{ showCode.share ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.share">
            <pre class="code-viewer"><code>// 检查分享功能是否可用
if (navigator.share) {
  // 分享文本
  navigator.share({
    title: '分享标题',
    text: '分享内容',
    url: 'https://example.com'
  })
    .then(() => console.log('分享成功'))
    .catch(error => console.log('分享失败:', error));

  // 分享文件
  navigator.share({
    title: '分享文件',
    files: [file]
  })
    .then(() => console.log('文件分享成功'))
    .catch(error => console.log('文件分享失败:', error));
}</code></pre>
          </div>
          <div class="demo-preview">
            <div class="share-demo">
              <div class="share-content">
                <input v-model="shareDemo.title" placeholder="分享标题">
                <textarea v-model="shareDemo.text" placeholder="分享内容"></textarea>
                <input v-model="shareDemo.url" placeholder="分享链接">
                <div class="file-upload">
                  <input type="file" @change="handleFileUpload" multiple>
                  <div class="file-list">
                    <div v-for="(file, index) in shareDemo.files" :key="index" class="file-item">
                      <span>{{ file.name }}</span>
                      <button @click="removeFile(index)">删除</button>
                    </div>
                  </div>
                </div>
              </div>
              <div class="share-controls">
                <button @click="shareContent" :disabled="!canShare">
                  分享内容
                </button>
                <button @click="shareFiles" :disabled="!canShareFiles">
                  分享文件
                </button>
              </div>
              <div class="share-status" :class="shareDemo.status">
                {{ shareDemo.statusMessage }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Notification API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Notification API</h3>
          <button class="code-toggle" @click="toggleCode('notification')">
            {{ showCode.notification ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.notification">
            <pre class="code-viewer"><code>// 请求通知权限
Notification.requestPermission()
  .then(permission => {
    console.log('通知权限:', permission);
  });

// 创建通知
const notification = new Notification('通知标题', {
  body: '通知内容',
  icon: '/path/to/icon.png',
  badge: '/path/to/badge.png',
  tag: 'notification-tag',
  data: { url: 'https://example.com' },
  vibrate: [200, 100, 200],
  actions: [
    { action: 'accept', title: '接受' },
    { action: 'reject', title: '拒绝' }
  ]
});

// 通知事件
notification.onclick = () => {
  window.focus();
  notification.close();
};

notification.onclose = () => {
  console.log('通知已关闭');
};

// 关闭通知
notification.close();</code></pre>
          </div>
          <div class="demo-preview">
            <div class="notification-demo">
              <div class="notification-form">
                <input v-model="notificationDemo.title" placeholder="通知标题">
                <textarea v-model="notificationDemo.body" placeholder="通知内容"></textarea>
                <input v-model="notificationDemo.icon" placeholder="图标URL">
                <div class="notification-options">
                  <label>
                    <input type="checkbox" v-model="notificationDemo.silent">
                    静音
                  </label>
                  <label>
                    <input type="checkbox" v-model="notificationDemo.requireInteraction">
                    需要交互
                  </label>
                  <label>
                    <input type="checkbox" v-model="notificationDemo.useServiceWorker">
                    使用 ServiceWorker（支持通知动作）
                  </label>
                </div>
                <div class="notification-actions" v-if="notificationDemo.useServiceWorker">
                  <div v-for="(action, index) in notificationDemo.actions" :key="index" class="action-item">
                    <input v-model="action.title" placeholder="动作标题">
                    <button @click="removeAction(index)">删除</button>
                  </div>
                  <button @click="addAction">添加动作</button>
                </div>
              </div>
              <div class="notification-controls">
                <button @click="requestPermission" :disabled="notificationDemo.permission === 'granted'">
                  请求权限
                </button>
                <button @click="showNotification" :disabled="!canShowNotification">
                  显示通知
                </button>
                <button @click="closeAllNotifications">
                  关闭所有通知
                </button>
              </div>
              <div class="notification-status" :class="notificationDemo.status">
                {{ notificationDemo.statusMessage }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Web Storage API -->
      <div class="demo-card">
        <div class="demo-header">
          <h3>Web Storage API</h3>
          <button class="code-toggle" @click="toggleCode('storage')">
            {{ showCode.storage ? '隐藏代码' : '查看代码' }}
          </button>
        </div>
        <div class="demo-content">
          <div class="code-block" v-if="showCode.storage">
            <pre class="code-viewer"><code>// LocalStorage
localStorage.setItem('key', 'value');
const value = localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();

// SessionStorage
sessionStorage.setItem('key', 'value');
const value = sessionStorage.getItem('key');
sessionStorage.removeItem('key');
sessionStorage.clear();

// 存储事件
window.addEventListener('storage', (event) => {
  console.log('存储变化:', {
    key: event.key,
    oldValue: event.oldValue,
    newValue: event.value,
    storageArea: event.storageArea
  });
});

// 存储配额
navigator.storage.estimate()
  .then(estimate => {
    console.log('存储使用情况:', estimate);
  });</code></pre>
          </div>
          <div class="demo-preview">
            <div class="storage-demo">
              <div class="storage-type">
                <label>
                  <input type="radio" v-model="storageDemo.type" value="local">
                  LocalStorage
                </label>
                <label>
                  <input type="radio" v-model="storageDemo.type" value="session">
                  SessionStorage
                </label>
              </div>
              <div class="storage-form">
                <input v-model="storageDemo.key" placeholder="键">
                <input v-model="storageDemo.value" placeholder="值">
                <button @click="saveItem">保存</button>
              </div>
              <div class="storage-list">
                <div v-for="(value, key) in storageDemo.items" :key="key" class="storage-item">
                  <span class="item-key">{{ key }}:</span>
                  <span class="item-value">{{ value }}</span>
                  <button @click="removeItem(key)">删除</button>
                </div>
              </div>
              <div class="storage-controls">
                <button @click="clearStorage">清空存储</button>
                <button @click="exportStorage">导出数据</button>
                <input type="file" @change="importStorage" accept=".json">
              </div>
              <div class="storage-info">
                <div class="info-item">
                  <span>已用空间:</span>
                  <span>{{ storageDemo.usage }} bytes</span>
                </div>
                <div class="info-item">
                  <span>项目数量:</span>
                  <span>{{ Object.keys(storageDemo.items).length }}</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted, onUnmounted } from 'vue'

// 代码显示状态
const showCode = ref({
  es6: false,
  array: false,
  async: false,
  oop: false,
  functional: false,
  module: false,
  error: false,
  regex: false,
  webrtc: false,
  websocket: false,
  canvas: false,
  bluetooth: false,
  speech: false,
  share: false,
  notification: false,
  storage: false
})

const toggleCode = (section) => {
  showCode.value[section] = !showCode.value[section]
}

// ES6+ 特性演示
const es6Demo = reactive({
  variables: 'let, const, var',
  arrowFunction: '(a, b) => a + b',
  templateString: 'Hello World!',
  destructuring: '{ title, content }',
  spread: '[1, 2, 3, 4, 5]',
  optionalChaining: 'user?.address?.city',
  nullishCoalescing: 'null ?? "默认值"',
  bigInt: '9007199254740991n + 1n',
  input: '',
  result: ''
})

es6Demo.processInput = () => {
  if (!es6Demo.input) return
  
  // 使用模板字符串
  es6Demo.result = `处理结果: ${es6Demo.input.toUpperCase()}`
  
  // 使用解构赋值
  const [first, ...rest] = es6Demo.input.split('')
  es6Demo.result += `\n首字母: ${first}, 其余: ${rest.join('')}`
  
  // 使用展开运算符
  const chars = [...es6Demo.input]
  es6Demo.result += `\n字符数组: [${chars.join(', ')}]`
  
  // 使用可选链和空值合并
  const obj = { a: { b: es6Demo.input } }
  const value = obj?.a?.b ?? '默认值'
  es6Demo.result += `\n可选链和空值合并: ${value}`
}

// 数组操作演示
const arrayDemo = reactive({
  original: [1, 2, 3, 4, 5],
  mapped: [],
  filtered: [],
  reduced: 0,
  found: null,
  flattened: [],
  newItem: ''
})

// 计算数组操作结果
const updateArrayResults = () => {
  arrayDemo.mapped = arrayDemo.original.map(x => x * 2)
  arrayDemo.filtered = arrayDemo.original.filter(x => x % 2 === 0)
  arrayDemo.reduced = arrayDemo.original.reduce((acc, cur) => acc + cur, 0)
  arrayDemo.found = arrayDemo.original.find(x => x > 3)
  arrayDemo.flattened = [1, [2, 3], [4, [5, 6]]].flat(2)
}

// 监听数组变化
watch(() => arrayDemo.original, updateArrayResults, { deep: true })

// 初始化数组结果
updateArrayResults()

// 添加元素到数组
const addToArray = () => {
  if (!arrayDemo.newItem) return
  const num = parseInt(arrayDemo.newItem)
  if (isNaN(num)) return
  
  arrayDemo.original.push(num)
  arrayDemo.newItem = ''
}

// 异步编程演示
const asyncDemo = reactive({
  status: '就绪',
  result: null,
  progress: 0,
  progressInterval: null
})

const runAsyncDemo = async (type) => {
  asyncDemo.status = 'running'
  asyncDemo.result = null
  asyncDemo.progress = 0
  
  // 启动进度条
  asyncDemo.progressInterval = setInterval(() => {
    if (asyncDemo.progress < 90) {
      asyncDemo.progress += 10
    }
  }, 200)

  try {
    switch (type) {
      case 'single':
        await new Promise(resolve => setTimeout(resolve, 2000))
        asyncDemo.result = '单个请求完成'
        break
      case 'multiple':
        const results = await Promise.all([
          new Promise(resolve => setTimeout(() => resolve('请求1'), 1000)),
          new Promise(resolve => setTimeout(() => resolve('请求2'), 1500)),
          new Promise(resolve => setTimeout(() => resolve('请求3'), 2000))
        ])
        asyncDemo.result = results.join(', ')
        break
      case 'race':
        const timeout = new Promise((_, reject) => 
          setTimeout(() => reject(new Error('超时')), 2000)
        )
        const data = new Promise(resolve => 
          setTimeout(() => resolve('数据'), 1000)
        )
        asyncDemo.result = await Promise.race([data, timeout])
        break
      case 'settled':
        const settledResults = await Promise.allSettled([
          new Promise(resolve => setTimeout(() => resolve('成功'), 1000)),
          new Promise((_, reject) => setTimeout(() => reject('失败'), 1500)),
          new Promise(resolve => setTimeout(() => resolve('成功'), 2000))
        ])
        asyncDemo.result = settledResults.map(r => r.status).join(', ')
        break
      case 'generator':
        function* numberGenerator() {
          yield 1
          yield 2
          yield 3
        }
        const gen = numberGenerator()
        asyncDemo.result = Array.from(gen).join(', ')
        break
    }
    asyncDemo.status = 'completed'
    asyncDemo.progress = 100
  } catch (error) {
    asyncDemo.status = 'error'
    asyncDemo.result = error.message
  } finally {
    clearInterval(asyncDemo.progressInterval)
  }
}

// 面向对象演示
const oopDemo = reactive({
  person: {
    name: '张三',
    age: 20,
    get info() {
      return `${this.name}, ${this.age}岁`
    },
    sayHello() {
      return `你好，我是${this.name}`
    },
    study() {
      return `${this.name}正在学习`
    }
  },
  account: {
    _balance: 0,
    deposit(amount) {
      this._balance += amount
      return this._balance
    },
    withdraw(amount) {
      if (amount > this._balance) {
        throw new Error('余额不足')
      }
      this._balance -= amount
      return this._balance
    },
    getBalance() {
      return this._balance
    }
  },
  newName: '',
  newAge: '',
  message: '',
  greeting: '',
  studyResult: ''
})

// 创建新对象
const createNewPerson = () => {
  if (!oopDemo.newName || !oopDemo.newAge) {
    oopDemo.message = '请输入姓名和年龄'
    return
  }
  
  const age = parseInt(oopDemo.newAge)
  if (isNaN(age)) {
    oopDemo.message = '年龄必须是数字'
    return
  }
  
  oopDemo.person = {
    name: oopDemo.newName,
    age: age,
    get info() {
      return `${this.name}, ${this.age}岁`
    },
    sayHello() {
      return `你好，我是${this.name}`
    },
    study() {
      return `${this.name}正在学习`
    }
  }
  
  oopDemo.message = `创建了新对象: ${oopDemo.person.name}, ${oopDemo.person.age}岁`
  oopDemo.newName = ''
  oopDemo.newAge = ''
}

// 面向对象方法调用
const sayHello = () => {
  oopDemo.greeting = oopDemo.person.sayHello()
}

const study = () => {
  oopDemo.studyResult = oopDemo.person.study()
}

const deposit = (amount) => {
  oopDemo.account.deposit(amount)
  oopDemo.message = `存款成功，当前余额: ${oopDemo.account.getBalance()}`
}

// 函数式编程演示
const functionalDemo = reactive({
  pureResult: null,
  curryResult: null,
  composeResult: null,
  input: '',
  customResult: null
})

// 纯函数示例
const add = (a, b) => a + b
const multiply = (a, b) => a * b
const square = x => x * x

// 柯里化函数
const curry = (fn) => {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args)
    }
    return (...moreArgs) => 
      curried.apply(this, args.concat(moreArgs))
  }
}

// 函数组合
const compose = (...fns) => x => 
  fns.reduceRight((v, f) => f(v), x)

const runFunctionalDemo = (type) => {
  switch (type) {
    case 'pure':
      functionalDemo.pureResult = add(5, 3)
      break
    case 'curry':
      const curriedAdd = curry(add)
      functionalDemo.curryResult = curriedAdd(5)(3)
      break
    case 'compose':
      const composed = compose(square, x => add(x, 1))
      functionalDemo.composeResult = composed(5)
      break
    case 'custom':
      if (!functionalDemo.input) return
      const num = parseInt(functionalDemo.input)
      if (isNaN(num)) return
      
      const customComposed = compose(
        square,
        x => multiply(x, 2),
        x => add(x, 10)
      )
      functionalDemo.customResult = customComposed(num)
      break
  }
}

// 模块化演示
const moduleDemo = reactive({
  result: null
})

const loadDynamicModule = async () => {
  moduleDemo.result = '加载中...'
  
  try {
    // 模拟动态导入
    await new Promise(resolve => setTimeout(resolve, 1000))
    moduleDemo.result = '模块加载成功!'
  } catch (error) {
    moduleDemo.result = `加载失败: ${error.message}`
  }
}

// 错误处理演示
const errorDemo = reactive({
  message: '',
  stack: ''
})

const triggerError = (type) => {
  errorDemo.message = ''
  errorDemo.stack = ''
  
  try {
    switch (type) {
      case 'standard':
        throw new Error('这是一个标准错误')
      case 'custom':
        throw new CustomError('这是一个自定义错误')
      case 'promise':
        Promise.reject(new Error('这是一个Promise错误'))
          .catch(error => {
            errorDemo.message = error.message
            errorDemo.stack = error.stack
          })
        return
      case 'async':
        (async () => {
          try {
            await Promise.reject(new Error('异步错误'))
          } catch (error) {
            errorDemo.message = error.message
            errorDemo.stack = error.stack
          }
        })()
        return
    }
  } catch (error) {
    errorDemo.message = error.message
    errorDemo.stack = error.stack
  }
}

// 正则表达式演示
const regexDemo = reactive({
  input: 'test@example.com', // 设置默认值
  pattern: 'email',
  customPattern: '',
  isValid: false,
  matches: []
})

const patterns = {
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  phone: /^1[3-9]\d{9}$/,
  date: /^(\d{4})-(\d{2})-(\d{2})$/
}

const testRegex = () => {
  if (regexDemo.pattern === 'custom') {
    testCustomRegex()
    return
  }
  
  const regex = patterns[regexDemo.pattern]
  regexDemo.isValid = regex.test(regexDemo.input)
  regexDemo.matches = []
  
  if (regexDemo.isValid) {
    const match = regexDemo.input.match(regex)
    if (match) {
      if (regexDemo.pattern === 'date') {
        const [_, year, month, day] = match
        regexDemo.matches = [`年份: ${year}`, `月份: ${month}`, `日期: ${day}`]
      } else {
        regexDemo.matches = [match[0]]
      }
    }
  }
}

const testCustomRegex = () => {
  try {
    if (!regexDemo.customPattern) {
      regexDemo.isValid = false
      regexDemo.matches = ['请输入自定义正则表达式']
      return
    }
    
    const regex = new RegExp(regexDemo.customPattern)
    regexDemo.isValid = regex.test(regexDemo.input)
    regexDemo.matches = []
    
    if (regexDemo.isValid) {
      const matches = regexDemo.input.match(regex)
      if (matches) {
        regexDemo.matches = matches
      }
    }
  } catch (error) {
    regexDemo.isValid = false
    regexDemo.matches = [`正则表达式错误: ${error.message}`]
  }
}

// 在组件挂载时初始化正则表达式测试
onMounted(() => {
  testRegex()
})

class CustomError extends Error {
  constructor(message) {
    super(message)
    this.name = 'CustomError'
  }
}

// WebRTC 演示
const webrtcDemo = reactive({
  isVideoActive: false,
  isScreenSharing: false,
  isConnected: false,
  connectionStatus: 'disconnected',
  statusMessage: '未连接',
  messages: [],
  messageInput: '',
  localStream: null,
  screenStream: null,
  peerConnection: null,
  dataChannel: null
})

const localVideo = ref(null)
const remoteVideo = ref(null)
const messages = ref(null)

// 初始化 WebRTC
const initWebRTC = async () => {
  try {
    webrtcDemo.peerConnection = new RTCPeerConnection({
      iceServers: [
        { urls: 'stun:stun.l.google.com:19302' }
      ]
    })

    // 处理远程流
    webrtcDemo.peerConnection.ontrack = (event) => {
      if (remoteVideo.value) {
        remoteVideo.value.srcObject = event.streams[0]
      }
    }

    // 处理 ICE 候选
    webrtcDemo.peerConnection.onicecandidate = (event) => {
      if (event.candidate) {
        // 在实际应用中，这里需要将候选发送给对等端
        console.log('新的 ICE 候选:', event.candidate)
      }
    }

    // 处理连接状态变化
    webrtcDemo.peerConnection.onconnectionstatechange = () => {
      updateConnectionStatus()
    }

    // 创建数据通道
    webrtcDemo.dataChannel = webrtcDemo.peerConnection.createDataChannel('chat')
    setupDataChannel(webrtcDemo.dataChannel)

    webrtcDemo.isConnected = true
    updateConnectionStatus()
  } catch (error) {
    console.error('WebRTC 初始化失败:', error)
    webrtcDemo.statusMessage = '初始化失败: ' + error.message
  }
}

// 设置数据通道
const setupDataChannel = (channel) => {
  channel.onopen = () => {
    console.log('数据通道已打开')
    webrtcDemo.messages.push({
      type: 'system',
      text: '连接已建立'
    })
  }

  channel.onclose = () => {
    console.log('数据通道已关闭')
    webrtcDemo.messages.push({
      type: 'system',
      text: '连接已关闭'
    })
  }

  channel.onmessage = (event) => {
    webrtcDemo.messages.push({
      type: 'received',
      text: event.data
    })
    scrollToBottom()
  }
}

// 开始视频
const startVideo = async () => {
  try {
    webrtcDemo.localStream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    })
    
    if (localVideo.value) {
      localVideo.value.srcObject = webrtcDemo.localStream
    }

    webrtcDemo.localStream.getTracks().forEach(track => {
      webrtcDemo.peerConnection.addTrack(track, webrtcDemo.localStream)
    })

    webrtcDemo.isVideoActive = true
    webrtcDemo.statusMessage = '视频已开启'
  } catch (error) {
    console.error('无法访问摄像头:', error)
    webrtcDemo.statusMessage = '无法访问摄像头: ' + error.message
  }
}

// 停止视频
const stopVideo = () => {
  if (webrtcDemo.localStream) {
    webrtcDemo.localStream.getTracks().forEach(track => track.stop())
    if (localVideo.value) {
      localVideo.value.srcObject = null
    }
    webrtcDemo.localStream = null
  }
  webrtcDemo.isVideoActive = false
  webrtcDemo.statusMessage = '视频已关闭'
}

// 开始屏幕共享
const startScreenShare = async () => {
  try {
    webrtcDemo.screenStream = await navigator.mediaDevices.getDisplayMedia({
      video: true
    })
    
    if (localVideo.value) {
      localVideo.value.srcObject = webrtcDemo.screenStream
    }

    webrtcDemo.screenStream.getTracks().forEach(track => {
      webrtcDemo.peerConnection.addTrack(track, webrtcDemo.screenStream)
    })

    webrtcDemo.isScreenSharing = true
    webrtcDemo.statusMessage = '屏幕共享已开启'
  } catch (error) {
    console.error('无法开始屏幕共享:', error)
    webrtcDemo.statusMessage = '无法开始屏幕共享: ' + error.message
  }
}

// 停止屏幕共享
const stopScreenShare = () => {
  if (webrtcDemo.screenStream) {
    webrtcDemo.screenStream.getTracks().forEach(track => track.stop())
    if (localVideo.value) {
      localVideo.value.srcObject = null
    }
    webrtcDemo.screenStream = null
  }
  webrtcDemo.isScreenSharing = false
  webrtcDemo.statusMessage = '屏幕共享已停止'
}

// 发送消息
const sendMessage = () => {
  if (!webrtcDemo.messageInput.trim() || !webrtcDemo.dataChannel) return

  webrtcDemo.dataChannel.send(webrtcDemo.messageInput)
  webrtcDemo.messages.push({
    type: 'sent',
    text: webrtcDemo.messageInput
  })
  webrtcDemo.messageInput = ''
  scrollToBottom()
}

// 滚动到底部
const scrollToBottom = () => {
  if (messages.value) {
    setTimeout(() => {
      messages.value.scrollTop = messages.value.scrollHeight
    }, 0)
  }
}

// 更新连接状态
const updateConnectionStatus = () => {
  if (!webrtcDemo.peerConnection) return

  const state = webrtcDemo.peerConnection.connectionState
  webrtcDemo.connectionStatus = state
  webrtcDemo.statusMessage = `连接状态: ${state}`
}

// 在组件挂载时初始化 WebRTC
onMounted(() => {
  initWebRTC()
})

// 在组件卸载时清理资源
onUnmounted(() => {
  stopVideo()
  stopScreenShare()
  if (webrtcDemo.peerConnection) {
    webrtcDemo.peerConnection.close()
  }
})

// WebSocket 演示
const websocketDemo = reactive({
  socket: null,
  isConnected: false,
  status: 'disconnected',
  statusMessage: '未连接',
  messages: [],
  messageInput: '',
  reconnectAttempts: 0,
  maxReconnectAttempts: 3,
  reconnectTimeout: null
})

const wsMessages = ref(null)

// 连接WebSocket
const connectWebSocket = () => {
  if (websocketDemo.socket) {
    websocketDemo.socket.close()
  }
  
  try {
    // 使用echo服务器进行演示
    websocketDemo.socket = new WebSocket('wss://echo.websocket.org')
    setupWebSocketHandlers()
    websocketDemo.status = 'connecting'
    websocketDemo.statusMessage = '正在连接...'
    websocketDemo.reconnectAttempts = 0
  } catch (error) {
    console.error('WebSocket连接失败:', error)
    websocketDemo.status = 'error'
    websocketDemo.statusMessage = '连接失败: ' + error.message
  }
}

// 设置WebSocket事件处理
const setupWebSocketHandlers = () => {
  if (!websocketDemo.socket) return
  
  websocketDemo.socket.onopen = () => {
    websocketDemo.isConnected = true
    websocketDemo.status = 'connected'
    websocketDemo.statusMessage = '已连接'
    websocketDemo.messages.push({
      type: 'system',
      text: '连接已建立'
    })
    scrollToBottom()
  }
  
  websocketDemo.socket.onmessage = (event) => {
    websocketDemo.messages.push({
      type: 'received',
      text: event.data
    })
    scrollToBottom()
  }
  
  websocketDemo.socket.onclose = () => {
    websocketDemo.isConnected = false
    websocketDemo.status = 'disconnected'
    websocketDemo.statusMessage = '连接已关闭'
    websocketDemo.messages.push({
      type: 'system',
      text: '连接已关闭'
    })
    scrollToBottom()
    
    // 尝试重新连接
    if (websocketDemo.reconnectAttempts < websocketDemo.maxReconnectAttempts) {
      websocketDemo.reconnectAttempts++
      websocketDemo.statusMessage = `连接断开，${websocketDemo.reconnectAttempts}秒后尝试重新连接...`
      websocketDemo.reconnectTimeout = setTimeout(() => {
        connectWebSocket()
      }, websocketDemo.reconnectAttempts * 1000)
    }
  }
  
  websocketDemo.socket.onerror = (error) => {
    console.error('WebSocket错误:', error)
    websocketDemo.status = 'error'
    websocketDemo.statusMessage = '连接错误'
  }
}

// 断开WebSocket连接
const disconnectWebSocket = () => {
  if (websocketDemo.socket) {
    websocketDemo.socket.close()
    websocketDemo.socket = null
  }
  
  if (websocketDemo.reconnectTimeout) {
    clearTimeout(websocketDemo.reconnectTimeout)
    websocketDemo.reconnectTimeout = null
  }
}

// 发送WebSocket消息
const sendWebSocketMessage = () => {
  if (!websocketDemo.messageInput.trim() || !websocketDemo.socket || websocketDemo.socket.readyState !== WebSocket.OPEN) return
  
  websocketDemo.socket.send(websocketDemo.messageInput)
  websocketDemo.messages.push({
    type: 'sent',
    text: websocketDemo.messageInput
  })
  websocketDemo.messageInput = ''
  scrollToBottom()
}

// 发送Ping消息
const sendPing = () => {
  if (!websocketDemo.socket || websocketDemo.socket.readyState !== WebSocket.OPEN) return
  
  websocketDemo.socket.send('ping')
  websocketDemo.messages.push({
    type: 'sent',
    text: 'ping'
  })
  scrollToBottom()
}

// Canvas 演示
const canvas = ref(null)
const canvasDemo = reactive({
  ctx: null,
  animationId: null,
  isAnimating: false,
  objects: [],
  shape: 'circle',
  color: '#00ff88',
  speed: 5,
  count: 5,
  mouseX: 0,
  mouseY: 0,
  isMouseDown: false,
  selectedObject: null
})

// 初始化Canvas
const initCanvas = () => {
  if (!canvas.value) return
  
  canvasDemo.ctx = canvas.value.getContext('2d')
  canvasDemo.ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
  canvasDemo.ctx.fillRect(0, 0, canvas.value.width, canvas.value.height)
  
  // 添加事件监听
  canvas.value.addEventListener('mousemove', handleCanvasMouseMove)
  canvas.value.addEventListener('mousedown', handleCanvasMouseDown)
  canvas.value.addEventListener('mouseup', handleCanvasMouseUp)
  canvas.value.addEventListener('mouseleave', handleCanvasMouseLeave)
  
  // 创建初始对象
  createObjects()
}

// 创建对象
const createObjects = () => {
  canvasDemo.objects = []
  
  for (let i = 0; i < canvasDemo.count; i++) {
    const size = 20 + Math.random() * 30
    canvasDemo.objects.push({
      x: Math.random() * (canvas.value.width - size * 2) + size,
      y: Math.random() * (canvas.value.height - size * 2) + size,
      size: size,
      dx: (Math.random() - 0.5) * canvasDemo.speed,
      dy: (Math.random() - 0.5) * canvasDemo.speed,
      color: canvasDemo.color,
      shape: canvasDemo.shape
    })
  }
}

// 处理鼠标移动
const handleCanvasMouseMove = (event) => {
  const rect = canvas.value.getBoundingClientRect()
  canvasDemo.mouseX = event.clientX - rect.left
  canvasDemo.mouseY = event.clientY - rect.top
  
  if (canvasDemo.isMouseDown && canvasDemo.selectedObject) {
    canvasDemo.selectedObject.x = canvasDemo.mouseX
    canvasDemo.selectedObject.y = canvasDemo.mouseY
  }
}

// 处理鼠标按下
const handleCanvasMouseDown = (event) => {
  const rect = canvas.value.getBoundingClientRect()
  const mouseX = event.clientX - rect.left
  const mouseY = event.clientY - rect.top
  
  // 检查是否点击了对象
  for (let i = canvasDemo.objects.length - 1; i >= 0; i--) {
    const obj = canvasDemo.objects[i]
    const distance = Math.sqrt(
      Math.pow(mouseX - obj.x, 2) + Math.pow(mouseY - obj.y, 2)
    )
    
    if (distance <= obj.size) {
      canvasDemo.isMouseDown = true
      canvasDemo.selectedObject = obj
      return
    }
  }
  
  // 如果没有点击对象，创建新对象
  const size = 20 + Math.random() * 30
  canvasDemo.objects.push({
    x: mouseX,
    y: mouseY,
    size: size,
    dx: 0,
    dy: 0,
    color: canvasDemo.color,
    shape: canvasDemo.shape
  })
}

// 处理鼠标释放
const handleCanvasMouseUp = () => {
  canvasDemo.isMouseDown = false
  canvasDemo.selectedObject = null
}

// 处理鼠标离开
const handleCanvasMouseLeave = () => {
  canvasDemo.isMouseDown = false
  canvasDemo.selectedObject = null
}

// 动画循环
const animateCanvas = () => {
  if (!canvasDemo.ctx || !canvas.value) return
  
  // 清除画布
  canvasDemo.ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  canvasDemo.ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
  canvasDemo.ctx.fillRect(0, 0, canvas.value.width, canvas.value.height)
  
  // 更新和绘制对象
  canvasDemo.objects.forEach(obj => {
    // 更新位置
    if (!canvasDemo.isMouseDown || obj !== canvasDemo.selectedObject) {
      obj.x += obj.dx
      obj.y += obj.dy
      
      // 边界检测
      if (obj.x + obj.size > canvas.value.width || obj.x - obj.size < 0) {
        obj.dx = -obj.dx
      }
      if (obj.y + obj.size > canvas.value.height || obj.y - obj.size < 0) {
        obj.dy = -obj.dy
      }
    }
    
    // 绘制对象
    canvasDemo.ctx.beginPath()
    
    switch (obj.shape) {
      case 'circle':
        canvasDemo.ctx.arc(obj.x, obj.y, obj.size, 0, Math.PI * 2)
        break
      case 'square':
        canvasDemo.ctx.rect(obj.x - obj.size, obj.y - obj.size, obj.size * 2, obj.size * 2)
        break
      case 'triangle':
        canvasDemo.ctx.moveTo(obj.x, obj.y - obj.size)
        canvasDemo.ctx.lineTo(obj.x + obj.size, obj.y + obj.size)
        canvasDemo.ctx.lineTo(obj.x - obj.size, obj.y + obj.size)
        canvasDemo.ctx.closePath()
        break
    }
    
    canvasDemo.ctx.fillStyle = obj.color
    canvasDemo.ctx.fill()
  })
  
  // 请求下一帧
  if (canvasDemo.isAnimating) {
    canvasDemo.animationId = requestAnimationFrame(animateCanvas)
  }
}

// 切换动画状态
const toggleCanvasAnimation = () => {
  canvasDemo.isAnimating = !canvasDemo.isAnimating
  
  if (canvasDemo.isAnimating) {
    animateCanvas()
  } else if (canvasDemo.animationId) {
    cancelAnimationFrame(canvasDemo.animationId)
  }
}

// 清除画布
const clearCanvas = () => {
  if (!canvasDemo.ctx || !canvas.value) return
  
  canvasDemo.ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  canvasDemo.ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
  canvasDemo.ctx.fillRect(0, 0, canvas.value.width, canvas.value.height)
  
  canvasDemo.objects = []
}

// 监听属性变化
watch(() => canvasDemo.shape, () => {
  canvasDemo.objects.forEach(obj => {
    obj.shape = canvasDemo.shape
  })
})

watch(() => canvasDemo.color, () => {
  canvasDemo.objects.forEach(obj => {
    obj.color = canvasDemo.color
  })
})

watch(() => canvasDemo.speed, () => {
  canvasDemo.objects.forEach(obj => {
    const speedFactor = canvasDemo.speed / 5
    obj.dx = (obj.dx / Math.abs(obj.dx || 1)) * speedFactor
    obj.dy = (obj.dy / Math.abs(obj.dy || 1)) * speedFactor
  })
})

watch(() => canvasDemo.count, () => {
  createObjects()
})

// 在组件挂载时初始化Canvas
onMounted(() => {
  initCanvas()
})

// 在组件卸载时清理资源
onUnmounted(() => {
  if (websocketDemo.socket) {
    websocketDemo.socket.close()
  }
  
  if (canvasDemo.animationId) {
    cancelAnimationFrame(canvasDemo.animationId)
  }
  
  if (canvas.value) {
    canvas.value.removeEventListener('mousemove', handleCanvasMouseMove)
    canvas.value.removeEventListener('mousedown', handleCanvasMouseDown)
    canvas.value.removeEventListener('mouseup', handleCanvasMouseUp)
    canvas.value.removeEventListener('mouseleave', handleCanvasMouseLeave)
  }
})

// Web Bluetooth API 演示
const bluetoothDemo = reactive({
  device: null,
  server: null,
  service: null,
  characteristic: null,
  isConnected: false,
  isScanning: false,
  status: 'disconnected',
  statusMessage: '未连接',
  services: [],
  data: null,
  logs: []
})

// 扫描蓝牙设备
const scanBluetoothDevices = async () => {
  if (!navigator.bluetooth) {
    addLog('您的浏览器不支持Web Bluetooth API')
    return
  }
  
  try {
    bluetoothDemo.isScanning = true
    bluetoothDemo.status = 'scanning'
    bluetoothDemo.statusMessage = '正在扫描设备...'
    addLog('开始扫描蓝牙设备')
    
    // 请求设备
    bluetoothDemo.device = await navigator.bluetooth.requestDevice({
      // 接受所有设备，实际应用中应该使用过滤器
      acceptAllDevices: true,
      optionalServices: ['battery_service', 'heart_rate']
    })
    
    addLog(`已选择设备: ${bluetoothDemo.device.name}`)
    bluetoothDemo.status = 'device_selected'
    bluetoothDemo.statusMessage = `已选择设备: ${bluetoothDemo.device.name}`
  } catch (error) {
    if (error.name === 'NotFoundError') {
      addLog('未选择设备或用户取消了选择')
    } else {
      addLog(`扫描错误: ${error.message}`)
    }
    bluetoothDemo.status = 'error'
    bluetoothDemo.statusMessage = `错误: ${error.message}`
  } finally {
    bluetoothDemo.isScanning = false
  }
}

// 连接到设备
const connectToDevice = async () => {
  if (!bluetoothDemo.device) {
    addLog('请先选择设备')
    return
  }
  
  try {
    bluetoothDemo.status = 'connecting'
    bluetoothDemo.statusMessage = '正在连接...'
    addLog('正在连接到设备...')
    
    // 连接到GATT服务器
    bluetoothDemo.server = await bluetoothDemo.device.gatt.connect()
    addLog('GATT服务器已连接')
    
    // 获取服务
    bluetoothDemo.services = []
    
    // 尝试获取电池服务
    try {
      const batteryService = await bluetoothDemo.server.getPrimaryService('battery_service')
      bluetoothDemo.services.push('battery_service')
      addLog('已获取电池服务')
      
      // 获取电池特征
      const batteryCharacteristic = await batteryService.getCharacteristic('battery_level')
      addLog('已获取电池特征')
      
      // 读取电池电量
      const batteryValue = await batteryCharacteristic.readValue()
      const batteryLevel = batteryValue.getUint8(0)
      bluetoothDemo.data = `电池电量: ${batteryLevel}%`
      addLog(`电池电量: ${batteryLevel}%`)
    } catch (error) {
      addLog(`无法获取电池服务: ${error.message}`)
    }
    
    // 尝试获取心率服务
    try {
      const heartRateService = await bluetoothDemo.server.getPrimaryService('heart_rate')
      bluetoothDemo.services.push('heart_rate')
      addLog('已获取心率服务')
      
      // 获取心率特征
      bluetoothDemo.characteristic = await heartRateService.getCharacteristic('heart_rate_measurement')
      addLog('已获取心率特征')
      
      // 开始通知
      await bluetoothDemo.characteristic.startNotifications()
      addLog('已开始心率通知')
      
      // 监听心率变化
      bluetoothDemo.characteristic.addEventListener('characteristicvaluechanged', handleHeartRateChanged)
    } catch (error) {
      addLog(`无法获取心率服务: ${error.message}`)
    }
    
    bluetoothDemo.isConnected = true
    bluetoothDemo.status = 'connected'
    bluetoothDemo.statusMessage = '已连接'
    addLog('设备连接成功')
  } catch (error) {
    bluetoothDemo.status = 'error'
    bluetoothDemo.statusMessage = `连接错误: ${error.message}`
    addLog(`连接错误: ${error.message}`)
  }
}

// 处理心率变化
const handleHeartRateChanged = (event) => {
  const value = event.target.value
  const heartRate = value.getUint8(1)
  bluetoothDemo.data = `心率: ${heartRate} BPM`
  addLog(`收到心率数据: ${heartRate} BPM`)
}

// 读取特征值
const readCharacteristic = async () => {
  if (!bluetoothDemo.characteristic) {
    addLog('没有可读取的特征')
    return
  }
  
  try {
    addLog('正在读取特征值...')
    const value = await bluetoothDemo.characteristic.readValue()
    const heartRate = value.getUint8(1)
    bluetoothDemo.data = `心率: ${heartRate} BPM`
    addLog(`读取心率: ${heartRate} BPM`)
  } catch (error) {
    addLog(`读取错误: ${error.message}`)
  }
}

// 断开设备连接
const disconnectDevice = () => {
  if (!bluetoothDemo.device || !bluetoothDemo.isConnected) {
    addLog('设备未连接')
    return
  }
  
  try {
    // 停止通知
    if (bluetoothDemo.characteristic) {
      bluetoothDemo.characteristic.stopNotifications()
      bluetoothDemo.characteristic.removeEventListener('characteristicvaluechanged', handleHeartRateChanged)
    }
    
    // 断开连接
    bluetoothDemo.device.gatt.disconnect()
    bluetoothDemo.isConnected = false
    bluetoothDemo.status = 'disconnected'
    bluetoothDemo.statusMessage = '已断开连接'
    addLog('设备已断开连接')
  } catch (error) {
    addLog(`断开连接错误: ${error.message}`)
  }
}

// 添加日志
const addLog = (message) => {
  const timestamp = new Date().toLocaleTimeString()
  bluetoothDemo.logs.unshift(`[${timestamp}] ${message}`)
  
  // 限制日志数量
  if (bluetoothDemo.logs.length > 10) {
    bluetoothDemo.logs.pop()
  }
}

// Web Speech API 演示
const speechDemo = reactive({
  // 语音识别
  recognition: null,
  isRecognizing: false,
  recognitionStatus: 'idle',
  recognitionStatusMessage: '就绪',
  interimTranscript: '',
  finalTranscript: '',
  recognitionLang: 'zh-CN',
  
  // 语音合成
  synthesis: null,
  utterance: null,
  isSynthesizing: false,
  isPaused: false,
  synthesisStatus: 'idle',
  synthesisStatusMessage: '就绪',
  synthesisText: '你好，这是语音合成测试。',
  synthesisLang: 'zh-CN',
  rate: 1.0,
  pitch: 1.0,
  volume: 1.0
})

// 初始化语音识别
const initSpeechRecognition = () => {
  if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) {
    console.error('您的浏览器不支持语音识别')
    return
  }
  
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition
  speechDemo.recognition = new SpeechRecognition()
  
  speechDemo.recognition.continuous = true
  speechDemo.recognition.interimResults = true
  speechDemo.recognition.lang = speechDemo.recognitionLang
  
  speechDemo.recognition.onstart = () => {
    speechDemo.isRecognizing = true
    speechDemo.recognitionStatus = 'recognizing'
    speechDemo.recognitionStatusMessage = '正在识别...'
  }
  
  speechDemo.recognition.onresult = (event) => {
    let interimTranscript = ''
    let finalTranscript = ''
    
    for (let i = event.resultIndex; i < event.results.length; i++) {
      const transcript = event.results[i][0].transcript
      
      if (event.results[i].isFinal) {
        finalTranscript += transcript
      } else {
        interimTranscript += transcript
      }
    }
    
    speechDemo.interimTranscript = interimTranscript
    speechDemo.finalTranscript = finalTranscript
  }
  
  speechDemo.recognition.onerror = (event) => {
    speechDemo.isRecognizing = false
    speechDemo.recognitionStatus = 'error'
    speechDemo.recognitionStatusMessage = `错误: ${event.error}`
  }
  
  speechDemo.recognition.onend = () => {
    speechDemo.isRecognizing = false
    speechDemo.recognitionStatus = 'idle'
    speechDemo.recognitionStatusMessage = '识别已结束'
  }
}

// 开始语音识别
const startRecognition = () => {
  if (!speechDemo.recognition) {
    initSpeechRecognition()
  }
  
  try {
    speechDemo.recognition.lang = speechDemo.recognitionLang
    speechDemo.recognition.start()
  } catch (error) {
    console.error('启动语音识别失败:', error)
    speechDemo.recognitionStatus = 'error'
    speechDemo.recognitionStatusMessage = `启动失败: ${error.message}`
  }
}

// 停止语音识别
const stopRecognition = () => {
  if (speechDemo.recognition) {
    speechDemo.recognition.stop()
  }
}

// 初始化语音合成
const initSpeechSynthesis = () => {
  if (!('speechSynthesis' in window)) {
    console.error('您的浏览器不支持语音合成')
    return
  }
  
  speechDemo.synthesis = window.speechSynthesis
  
  // 监听语音合成事件
  speechDemo.synthesis.onstart = () => {
    speechDemo.isSynthesizing = true
    speechDemo.isPaused = false
    speechDemo.synthesisStatus = 'synthesizing'
    speechDemo.synthesisStatusMessage = '正在合成...'
  }
  
  speechDemo.synthesis.onend = () => {
    speechDemo.isSynthesizing = false
    speechDemo.isPaused = false
    speechDemo.synthesisStatus = 'idle'
    speechDemo.synthesisStatusMessage = '合成已结束'
  }
  
  speechDemo.synthesis.onerror = (event) => {
    speechDemo.isSynthesizing = false
    speechDemo.isPaused = false
    speechDemo.synthesisStatus = 'error'
    speechDemo.synthesisStatusMessage = `错误: ${event.error}`
  }
}

// 语音合成可用 voice 列表
const voices = ref([])

const loadVoices = () => {
  voices.value = window.speechSynthesis.getVoices()
}

if ('speechSynthesis' in window) {
  window.speechSynthesis.onvoiceschanged = loadVoices
  loadVoices()
}

const startSynthesis = () => {
  if (!speechDemo.synthesis) {
    initSpeechSynthesis()
  }
  if (!speechDemo.synthesisText || !speechDemo.synthesisText.trim()) {
    speechDemo.synthesisStatus = 'error'
    speechDemo.synthesisStatusMessage = '请输入要合成的文本'
    return
  }
  if (!voices.value.length) {
    speechDemo.synthesisStatus = 'error'
    speechDemo.synthesisStatusMessage = '语音引擎未就绪，请稍后重试或刷新页面'
    loadVoices()
    return
  }
  // 取消之前的合成
  speechDemo.synthesis.cancel()
  // 创建新的语音合成实例
  speechDemo.utterance = new SpeechSynthesisUtterance(speechDemo.synthesisText)
  speechDemo.utterance.lang = speechDemo.synthesisLang
  speechDemo.utterance.rate = speechDemo.rate
  speechDemo.utterance.pitch = speechDemo.pitch
  speechDemo.utterance.volume = speechDemo.volume
  // 自动为当前语言选择合适的 voice
  const matchedVoice = voices.value.find(v => v.lang === speechDemo.synthesisLang)
  if (matchedVoice) {
    speechDemo.utterance.voice = matchedVoice
  }
  // 开始合成
  speechDemo.synthesis.speak(speechDemo.utterance)
}

// 暂停语音合成
const pauseSynthesis = () => {
  if (speechDemo.synthesis && speechDemo.isSynthesizing) {
    speechDemo.synthesis.pause()
    speechDemo.isPaused = true
    speechDemo.synthesisStatus = 'paused'
    speechDemo.synthesisStatusMessage = '已暂停'
  }
}

// 继续语音合成
const resumeSynthesis = () => {
  if (speechDemo.synthesis && speechDemo.isPaused) {
    speechDemo.synthesis.resume()
    speechDemo.isPaused = false
    speechDemo.synthesisStatus = 'synthesizing'
    speechDemo.synthesisStatusMessage = '正在合成...'
  }
}

// 取消语音合成
const cancelSynthesis = () => {
  if (speechDemo.synthesis) {
    speechDemo.synthesis.cancel()
    speechDemo.isSynthesizing = false
    speechDemo.isPaused = false
    speechDemo.synthesisStatus = 'idle'
    speechDemo.synthesisStatusMessage = '已取消'
  }
}

// 监听语音识别语言变化
watch(() => speechDemo.recognitionLang, (newLang) => {
  if (speechDemo.recognition) {
    speechDemo.recognition.lang = newLang
  }
})

// 监听语音合成语言变化
watch(() => speechDemo.synthesisLang, (newLang) => {
  if (speechDemo.utterance) {
    speechDemo.utterance.lang = newLang
  }
})

// 在组件挂载时初始化语音API
onMounted(() => {
  initSpeechRecognition()
  initSpeechSynthesis()
})

// 在组件卸载时清理资源
onUnmounted(() => {
  if (speechDemo.recognition) {
    speechDemo.recognition.stop()
  }
  
  if (speechDemo.synthesis) {
    speechDemo.synthesis.cancel()
  }
})

// Web Share API 演示
const shareDemo = reactive({
  title: '',
  text: '',
  url: '',
  files: [],
  status: 'idle',
  statusMessage: '就绪',
  canShare: false,
  canShareFiles: false
})

const canShare = computed(() => {
  return shareDemo.title.trim() || shareDemo.text.trim() || shareDemo.url.trim()
})

const canShareFiles = computed(() => {
  return shareDemo.files.length > 0
})

const shareContent = () => {
  if (!canShare.value) {
    shareDemo.status = 'error'
    shareDemo.statusMessage = '请填写分享内容'
    return
  }
  
  navigator.share({
    title: shareDemo.title,
    text: shareDemo.text,
    url: shareDemo.url
  })
    .then(() => {
      shareDemo.status = 'success'
      shareDemo.statusMessage = '分享成功'
      shareDemo.title = ''
      shareDemo.text = ''
      shareDemo.url = ''
      shareDemo.files = []
    })
    .catch(error => {
      shareDemo.status = 'error'
      shareDemo.statusMessage = `分享失败: ${error.message}`
    })
}

const handleFileUpload = (event) => {
  const files = event.target.files
  shareDemo.files = Array.from(files)
}

const removeFile = (index) => {
  shareDemo.files.splice(index, 1)
}

// Web Notification API 演示
const notificationDemo = reactive({
  title: '',
  body: '',
  icon: '',
  silent: false,
  requireInteraction: false,
  permission: Notification.permission,
  status: 'idle',
  statusMessage: '就绪',
  useServiceWorker: false,
  actions: [{ title: '接受' }, { title: '拒绝' }]
})

const canShowNotification = computed(() => {
  return notificationDemo.permission === 'granted' && 
         (notificationDemo.title.trim() || notificationDemo.body.trim() || notificationDemo.icon.trim())
})

const requestPermission = async () => {
  try {
    const permission = await Notification.requestPermission()
    notificationDemo.permission = permission
    notificationDemo.status = permission === 'granted' ? 'success' : 'error'
    notificationDemo.statusMessage = `通知权限: ${permission}`
  } catch (error) {
    notificationDemo.status = 'error'
    notificationDemo.statusMessage = `请求通知权限失败: ${error.message}`
  }
}

const showNotification = async () => {
  if (!canShowNotification.value) {
    notificationDemo.status = 'error'
    notificationDemo.statusMessage = notificationDemo.permission !== 'granted' 
      ? '请先请求通知权限' 
      : '请填写通知内容'
    return
  }
  
  try {
    const options = {
      body: notificationDemo.body,
      icon: notificationDemo.icon || undefined,
      silent: notificationDemo.silent,
      requireInteraction: notificationDemo.requireInteraction,
      data: { url: 'https://example.com' },
      vibrate: [200, 100, 200]
    }

    if (notificationDemo.useServiceWorker) {
      // 使用 ServiceWorker 显示通知
      if ('serviceWorker' in navigator) {
        const registration = await navigator.serviceWorker.register('/notification-worker.js')
        await registration.showNotification(notificationDemo.title, {
          ...options,
          actions: notificationDemo.actions.map(action => ({
            action: action.title.toLowerCase(),
            title: action.title
          }))
        })
      } else {
        throw new Error('您的浏览器不支持 ServiceWorker')
      }
    } else {
      // 使用普通通知
      const notification = new Notification(notificationDemo.title, options)
      
      notification.onclick = () => {
        window.focus()
        notification.close()
      }
      
      notification.onclose = () => {
        notificationDemo.status = 'success'
        notificationDemo.statusMessage = '通知已关闭'
      }
    }
    
    notificationDemo.status = 'success'
    notificationDemo.statusMessage = '通知已显示'
    
    // 重置表单
    notificationDemo.title = ''
    notificationDemo.body = ''
    notificationDemo.icon = ''
    notificationDemo.silent = false
    notificationDemo.requireInteraction = false
    notificationDemo.actions = [{ title: '接受' }, { title: '拒绝' }]
  } catch (error) {
    notificationDemo.status = 'error'
    notificationDemo.statusMessage = `显示通知失败: ${error.message}`
  }
}

const closeAllNotifications = () => {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.getRegistrations().then(registrations => {
      registrations.forEach(registration => {
        registration.active?.postMessage({ type: 'CLOSE_ALL_NOTIFICATIONS' })
      })
    })
  }
  Notification.close()
  notificationDemo.status = 'success'
  notificationDemo.statusMessage = '所有通知已关闭'
}

const removeAction = (index) => {
  notificationDemo.actions.splice(index, 1)
}

const addAction = () => {
  notificationDemo.actions.push({ title: '新动作' })
}

// 在组件挂载时检查通知权限
onMounted(() => {
  notificationDemo.permission = Notification.permission
  notificationDemo.statusMessage = `通知权限: ${Notification.permission}`
})

// Web Storage API 演示
const storageDemo = reactive({
  type: 'local',
  key: '',
  value: '',
  items: {}
})

const saveItem = () => {
  if (!storageDemo.key.trim() || !storageDemo.value.trim()) return;
  if (storageDemo.type === 'local') {
    localStorage.setItem(storageDemo.key, storageDemo.value);
  } else {
    sessionStorage.setItem(storageDemo.key, storageDemo.value);
  }
  storageDemo.items[storageDemo.key] = storageDemo.value;
  storageDemo.key = '';
  storageDemo.value = '';
};

const removeItem = (key) => {
  if (storageDemo.type === 'local') {
    localStorage.removeItem(key);
  } else {
    sessionStorage.removeItem(key);
  }
  delete storageDemo.items[key];
};

const clearStorage = () => {
  if (storageDemo.type === 'local') {
    localStorage.clear()
    storageDemo.items = {}
  } else if (storageDemo.type === 'session') {
    sessionStorage.clear()
    storageDemo.items = {}
  }
  
  storageDemo.status = 'success'
  storageDemo.statusMessage = '所有数据已清除'
}

const exportStorage = () => {
  const data = storageDemo.type === 'local' ? localStorage.getItem('key') : sessionStorage.getItem('key')
  const blob = new Blob([data], { type: 'text/plain' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `storage-${storageDemo.type}.txt`
  a.click()
  URL.revokeObjectURL(url)
}

const importStorage = (event) => {
  const file = event.target.files[0]
  if (!file) return
  
  const reader = new FileReader()
  reader.onload = (e) => {
    const data = e.target.result
    if (storageDemo.type === 'local') {
      localStorage.setItem('key', data)
      storageDemo.items = { key: data }
    } else if (storageDemo.type === 'session') {
      sessionStorage.setItem('key', data)
      storageDemo.items = { key: data }
    }
    
    storageDemo.status = 'success'
    storageDemo.statusMessage = '数据已导入'
    storageDemo.key = ''
    storageDemo.value = ''
  }
  reader.readAsText(file)
}

// Web Worker API 演示
const workerDemo = reactive({
  taskType: 'fibonacci',
  input: '',
  isRunning: false,
  status: 'idle',
  statusMessage: '就绪',
  result: null,
  mainThreadTime: 0,
  workerTime: 0,
  worker: null
})

const startWorkerTask = () => {
  if (!workerDemo.input) {
    workerDemo.status = 'error'
    workerDemo.statusMessage = '请输入数字'
    return
  }

  workerDemo.isRunning = true
  workerDemo.status = 'running'
  workerDemo.statusMessage = '计算中...'
  workerDemo.result = null

  // 创建 Worker
  workerDemo.worker = new Worker(new URL('./worker.js', import.meta.url))

  // 记录主线程开始时间
  const mainStartTime = performance.now()

  // 发送消息给 Worker
  workerDemo.worker.postMessage({
    type: workerDemo.taskType,
    input: parseInt(workerDemo.input)
  })

  // 监听 Worker 消息
  workerDemo.worker.onmessage = (event) => {
    const mainEndTime = performance.now()
    workerDemo.mainThreadTime = Math.round(mainEndTime - mainStartTime)
    workerDemo.workerTime = event.data.time
    workerDemo.result = event.data.result
    workerDemo.isRunning = false
    workerDemo.status = 'success'
    workerDemo.statusMessage = '计算完成'
  }

  // 监听 Worker 错误
  workerDemo.worker.onerror = (error) => {
    workerDemo.isRunning = false
    workerDemo.status = 'error'
    workerDemo.statusMessage = `计算错误: ${error.message}`
  }
}

const stopWorkerTask = () => {
  if (workerDemo.worker) {
    workerDemo.worker.terminate()
    workerDemo.worker = null
  }
  workerDemo.isRunning = false
  workerDemo.status = 'idle'
  workerDemo.statusMessage = '已停止'
}

// Web Animation API 演示
const animationDemo = reactive({
  type: 'bounce',
  duration: 1000,
  iterations: 1,
  isPlaying: false,
  animation: null
})

const animatedElement = ref(null)

const startAnimation = () => {
  if (!animatedElement.value) return

  const keyframes = {
    bounce: [
      { transform: 'translateY(0)' },
      { transform: 'translateY(-100px)' },
      { transform: 'translateY(0)' }
    ],
    rotate: [
      { transform: 'rotate(0deg)' },
      { transform: 'rotate(360deg)' }
    ],
    scale: [
      { transform: 'scale(1)' },
      { transform: 'scale(1.5)' },
      { transform: 'scale(1)' }
    ],
    color: [
      { backgroundColor: '#4CAF50' },
      { backgroundColor: '#2196F3' },
      { backgroundColor: '#4CAF50' }
    ]
  }

  const options = {
    duration: animationDemo.duration,
    iterations: animationDemo.iterations,
    easing: 'ease-in-out',
    fill: 'forwards'
  }

  // 确保之前的动画被取消
  if (animationDemo.animation) {
    animationDemo.animation.cancel()
    animationDemo.animation = null
  }

  try {
    // 重置元素样式
    animatedElement.value.style.transform = ''
    animatedElement.value.style.backgroundColor = '#4CAF50'

    // 创建新动画
    animationDemo.animation = animatedElement.value.animate(
      keyframes[animationDemo.type],
      options
    )

    // 设置动画事件处理
    animationDemo.animation.onfinish = () => {
      animationDemo.isPlaying = false
      // 保持最终状态
      if (animationDemo.type === 'color') {
        animatedElement.value.style.backgroundColor = '#4CAF50'
      } else {
        animatedElement.value.style.transform = ''
      }
    }

    animationDemo.animation.oncancel = () => {
      animationDemo.isPlaying = false
      // 重置样式
      animatedElement.value.style.transform = ''
      animatedElement.value.style.backgroundColor = '#4CAF50'
    }

    animationDemo.isPlaying = true
  } catch (error) {
    console.error('动画创建失败:', error)
    animationDemo.isPlaying = false
  }
}

const stopAnimation = () => {
  if (animationDemo.animation) {
    animationDemo.animation.cancel()
    animationDemo.animation = null
  }
  // 重置样式
  if (animatedElement.value) {
    animatedElement.value.style.transform = ''
    animatedElement.value.style.backgroundColor = '#4CAF50'
  }
  animationDemo.isPlaying = false
}

// 监听动画类型变化
watch(() => animationDemo.type, () => {
  if (animationDemo.isPlaying) {
    startAnimation()
  }
})

// 监听动画参数变化
watch([() => animationDemo.duration, () => animationDemo.iterations], () => {
  if (animationDemo.isPlaying) {
    startAnimation()
  }
})



</script>

<style scoped>
.storage-type {
  display: flex;
  gap: 1.5rem;
  align-items: center;
  margin-bottom: 0.5rem;
}
.storage-type label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 1rem;
  white-space: nowrap;
  margin-bottom: 0;
}
.storage-type input[type="radio"] {
  accent-color: #00ff88;
  width: 18px;
  height: 18px;
  margin: 0 4px 0 0;
}
@media (max-width: 600px) {
  .storage-type {
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
  }
}
.notification-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.notification-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 100%;
}

.notification-form input,
.notification-form textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.1);
  color: inherit;
}

.notification-form textarea {
  min-height: 60px;
  resize: vertical;
  max-height: 120px;
}

.notification-options {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: center;
  margin-top: 0.5rem;
}

.notification-options label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 1rem;
  white-space: nowrap;
  margin-bottom: 0;
}

.notification-options .sw-label {
  flex-basis: 100%;
  margin-top: 0.2rem;
  white-space: normal;
}

.notification-options input[type="checkbox"] {
  accent-color: #00ff88;
  width: 18px;
  height: 18px;
  margin: 0 4px 0 0;
}

@media (max-width: 600px) {
  .notification-options {
    flex-direction: column;
    gap: 0.5rem;
    align-items: flex-start;
  }
  .notification-options .sw-label {
    margin-top: 0.2rem;
  }
}

.notification-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.action-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.action-item input {
  flex: 1;
  min-width: 0;
}

.action-item button {
  flex-shrink: 0;
  padding: 0.25rem 0.5rem;
  font-size: 0.9em;
}

.notification-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.notification-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  font-size: 0.9em;
  word-break: break-word;
  margin-top: 0.5rem;
}

.share-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.share-content {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 100%;
}

.share-content input,
.share-content textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.1);
  color: inherit;
}

.share-content textarea {
  min-height: 80px;
  resize: vertical;
  max-height: 200px;
}

.file-upload {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}

.file-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  max-width: 100%;
  margin-top: 0.5rem;
}

.file-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
  max-width: 100%;
  overflow: hidden;
}

.file-item span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-item button {
  flex-shrink: 0;
  padding: 0.25rem 0.5rem;
  font-size: 0.9em;
}

.share-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.share-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  font-size: 0.9em;
  word-break: break-word;
}
.javascript-demo {
  padding: 2rem;
}

.section-title {
  font-size: 2.5rem;
  margin-bottom: 2rem;
  text-align: center;
  background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.demo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.demo-card {
  background: rgba(0, 0, 0, 0.3);
  border-radius: 15px;
  padding: 1.5rem;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.demo-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}

.demo-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.demo-header h3 {
  font-size: 1.5rem;
  margin: 0;
  color: var(--primary-color);
}

.code-toggle {
  background: rgba(0, 255, 136, 0.1);
  border: 1px solid rgba(0, 255, 136, 0.3);
  color: #00ff88;
  padding: 0.5rem 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.code-toggle:hover {
  background: rgba(0, 255, 136, 0.2);
}

.demo-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.code-block {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  overflow: hidden;
}

.code-viewer {
  width: 100%;
  margin: 0;
  padding: 1rem;
  background: transparent;
  color: #b8e0d2;
  font-family: 'Fira Code', monospace;
  font-size: 0.9rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
}

.demo-preview {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.feature-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.feature-item {
  display: flex;
  justify-content: space-between;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.feature-item:hover {
  background: rgba(0, 0, 0, 0.3);
}

.feature-label {
  color: var(--primary-color);
}

.feature-value {
  font-family: monospace;
}

.interactive-demo {
  margin-top: 1rem;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
}

.input-group {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.input-group input {
  flex: 1;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.result-display {
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  white-space: pre-wrap;
}

.array-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.array-controls {
  display: flex;
  gap: 0.5rem;
}

.array-display {
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  font-family: monospace;
}

.array-results {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.result-item {
  display: flex;
  justify-content: space-between;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.result-item:hover {
  background: rgba(0, 0, 0, 0.3);
}

.result-label {
  color: var(--primary-color);
}

.result-value {
  font-family: monospace;
}

.async-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.status-box {
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  text-align: center;
  transition: background-color 0.3s ease;
}

.status-box.running {
  background: rgba(0, 255, 136, 0.1);
  color: #00ff88;
}

.status-box.completed {
  background: rgba(0, 149, 255, 0.1);
  color: #0095ff;
}

.status-box.error {
  background: rgba(255, 0, 0, 0.1);
  color: #ff4444;
}

.progress-bar {
  height: 5px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
  overflow: hidden;
}

.progress {
  height: 100%;
  background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
  transition: width 0.3s ease;
}

.controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 5px;
  background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
  color: var(--text-color);
  cursor: pointer;
  transition: all 0.3s ease;
}

button:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 255, 136, 0.2);
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.result-box {
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  text-align: center;
  transition: background-color 0.3s ease;
}

.result-box:hover {
  background: rgba(0, 0, 0, 0.3);
}

.oop-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.object-display {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.object-display:hover {
  background: rgba(0, 0, 0, 0.3);
}

.object-info {
  flex: 1;
}

.object-info p {
  margin: 0.5rem 0;
}

.result-text {
  margin-top: 0.5rem;
  padding: 0.5rem;
  background: rgba(0, 255, 136, 0.1);
  border-radius: 5px;
  color: #00ff88;
  font-weight: 500;
}

.object-actions {
  display: flex;
  gap: 0.5rem;
}

.object-creation {
  margin-top: 1rem;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  width: 100%;
  box-sizing: border-box;
}

.object-creation h4 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-color);
}

.input-group {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.input-group input {
  flex: 1;
  min-width: 100px;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.input-group button {
  white-space: nowrap;
}

.functional-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.function-display {
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.function-display:hover {
  background: rgba(0, 0, 0, 0.3);
}

.function-info {
  margin-bottom: 1rem;
}

.function-actions {
  display: flex;
  gap: 0.5rem;
}

.function-input {
  margin-top: 1rem;
  display: flex;
  gap: 0.5rem;
}

.module-demo {
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.module-demo:hover {
  background: rgba(0, 0, 0, 0.3);
}

.module-info {
  margin-bottom: 1rem;
}

.module-info ul {
  margin: 0.5rem 0;
  padding-left: 1.5rem;
}

.module-actions {
  margin-top: 1rem;
}

.module-result {
  margin-top: 1rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  text-align: center;
}

.error-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.error-display {
  padding: 0.5rem;
  background: rgba(255, 0, 0, 0.1);
  border: 1px solid rgba(255, 0, 0, 0.3);
  border-radius: 5px;
  color: #ff4444;
  text-align: center;
  transition: all 0.3s ease;
}

.error-display:hover {
  background: rgba(255, 0, 0, 0.2);
}

.error-stack {
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 5px;
  overflow-x: auto;
}

.error-stack pre {
  margin: 0;
  font-family: monospace;
  font-size: 0.8rem;
  white-space: pre-wrap;
  word-break: break-all;
}

.regex-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.regex-input {
  display: flex;
  gap: 0.5rem;
}

.regex-input input {
  flex: 1;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.regex-input select {
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.regex-custom {
  margin-top: 0.5rem;
}

.regex-result {
  padding: 0.5rem;
  text-align: center;
  border-radius: 5px;
  background: rgba(255, 0, 0, 0.1);
  color: #ff4444;
  transition: all 0.3s ease;
}

.regex-result.valid {
  background: rgba(0, 255, 0, 0.1);
  color: #00ff00;
}

.regex-matches {
  margin-top: 1rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
}

.regex-matches h4 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-color);
}

.regex-matches ul {
  margin: 0;
  padding-left: 1.5rem;
}

.webrtc-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.media-controls {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.video-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.video-container video {
  width: 100%;
  max-width: 100%;
  height: auto;
  max-height: 200px;
  background: #000;
  border-radius: 8px;
  object-fit: cover;
}

.control-buttons {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.data-channel {
  margin-top: 1rem;
}

.chat-box {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  padding: 1rem;
  max-height: 300px;
  overflow: hidden;
}

.messages {
  height: 200px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.message {
  padding: 0.5rem;
  border-radius: 4px;
  max-width: 80%;
  word-break: break-word;
}

.message.sent {
  background: rgba(0, 255, 136, 0.1);
  align-self: flex-end;
}

.message.received {
  background: rgba(0, 149, 255, 0.1);
  align-self: flex-start;
}

.message.system {
  background: rgba(255, 255, 255, 0.1);
  align-self: center;
  font-size: 0.9em;
}

.input-area {
  display: flex;
  gap: 0.5rem;
}

.input-area input {
  flex: 1;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.connection-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  font-size: 0.9em;
}

.connection-status.connected {
  background: rgba(0, 255, 136, 0.1);
  color: #00ff88;
}

.connection-status.disconnected {
  background: rgba(255, 0, 0, 0.1);
  color: #ff4444;
}

.connection-status.connecting {
  background: rgba(255, 255, 0, 0.1);
  color: #ffff00;
}

.websocket-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.chat-container {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  padding: 1rem;
  max-height: 300px;
  overflow: hidden;
}

.messages {
  height: 200px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.message {
  padding: 0.5rem;
  border-radius: 4px;
  max-width: 80%;
  word-break: break-word;
}

.message.sent {
  background: rgba(0, 255, 136, 0.1);
  align-self: flex-end;
}

.message.received {
  background: rgba(0, 149, 255, 0.1);
  align-self: flex-start;
}

.message.system {
  background: rgba(255, 255, 255, 0.1);
  align-self: center;
  font-size: 0.9em;
}

.input-area {
  display: flex;
  gap: 0.5rem;
}

.input-area input {
  flex: 1;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.canvas-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

canvas {
  width: 100%;
  height: 300px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  cursor: pointer;
}

.canvas-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
}

.control-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.control-group label {
  font-size: 0.9em;
  color: var(--primary-color);
}

.control-group select,
.control-group input {
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

.canvas-interaction {
  text-align: center;
  font-size: 0.9em;
  color: rgba(255, 255, 255, 0.7);
}

@media (max-width: 768px) {
  .video-container {
    grid-template-columns: 1fr;
  }
  
  .video-container video {
    max-height: 150px;
  }
  
  .chat-box {
    max-height: 250px;
  }
  
  .messages {
    height: 150px;
  }
  
  .canvas-controls {
    flex-direction: column;
  }
}

.bluetooth-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.device-info, .service-info, .data-display {
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
}

.device-info h4, .service-info h4, .data-display h4 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-color);
}

.service-info ul {
  margin: 0;
  padding-left: 1.5rem;
}

.data-value {
  font-family: monospace;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  text-align: center;
}

.bluetooth-log {
  margin-top: 1rem;
}

.bluetooth-log h4 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-color);
}

.log-container {
  height: 150px;
  overflow-y: auto;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  padding: 0.5rem;
}

.log-entry {
  font-family: monospace;
  font-size: 0.8em;
  padding: 0.25rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.connection-status.scanning {
  background: rgba(255, 255, 0, 0.1);
  color: #ffff00;
}

.connection-status.device_selected {
  background: rgba(0, 149, 255, 0.1);
  color: #0095ff;
}

.speech-demo {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.speech-section {
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
}

.speech-section h4 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-color);
}

.recognition-status, .synthesis-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  margin-bottom: 1rem;
}

.recognition-status.recognizing, .synthesis-status.synthesizing {
  background: rgba(0, 255, 136, 0.1);
  color: #00ff88;
}

.recognition-status.idle, .synthesis-status.idle {
  background: rgba(0, 0, 0, 0.3);
  color: rgba(255, 255, 255, 0.7);
}

.recognition-status.error, .synthesis-status.error {
  background: rgba(255, 0, 0, 0.1);
  color: #ff4444;
}

.synthesis-status.paused {
  background: rgba(255, 255, 0, 0.1);
  color: #ffff00;
}

.recognition-result {
  margin-bottom: 1rem;
  min-height: 100px;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 4px;
}

.interim-result {
  color: rgba(255, 255, 255, 0.7);
  font-style: italic;
}

.final-result {
  margin-top: 0.5rem;
  font-weight: bold;
}

.recognition-controls, .synthesis-controls {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.synthesis-input {
  margin-bottom: 1rem;
}

.synthesis-input textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
  resize: vertical;
}

.voice-settings {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.setting-group {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.setting-group label {
  min-width: 60px;
  font-size: 0.9em;
}

.setting-group input[type="range"] {
  flex: 1;
}

.setting-group span {
  min-width: 30px;
  text-align: right;
  font-size: 0.9em;
}

.setting-group select {
  flex: 1;
  padding: 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-color);
}

@media (max-width: 768px) {
  .recognition-controls, .synthesis-controls {
    flex-direction: column;
  }
  
  .setting-group {
    flex-direction: column;
    align-items: flex-start;
  }
  
  .setting-group label {
    margin-bottom: 0.25rem;
  }
}

.share-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.share-content {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 100%;
}

.share-content input,
.share-content textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.1);
  color: inherit;
}

.share-content textarea {
  min-height: 80px;
  resize: vertical;
  max-height: 200px;
}

.file-upload {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}

.file-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  max-width: 100%;
  margin-top: 0.5rem;
}

.file-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
  max-width: 100%;
  overflow: hidden;
}

.file-item span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-item button {
  flex-shrink: 0;
  padding: 0.25rem 0.5rem;
  font-size: 0.9em;
}

.share-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.share-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  font-size: 0.9em;
  word-break: break-word;
}

.notification-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.notification-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 100%;
}

.notification-form input,
.notification-form textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.1);
  color: inherit;
}

.notification-form textarea {
  min-height: 60px;
  resize: vertical;
  max-height: 120px;
}

.notification-options {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 0.5rem;
}

.notification-options label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}

.notification-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.action-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

.action-item input {
  flex: 1;
  min-width: 0;
}

.action-item button {
  flex-shrink: 0;
  padding: 0.25rem 0.5rem;
  font-size: 0.9em;
}

.notification-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.notification-status {
  padding: 0.5rem;
  text-align: center;
  border-radius: 4px;
  font-size: 0.9em;
  word-break: break-word;
  margin-top: 0.5rem;
}

.storage-demo {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 100%;
  overflow: hidden;
}

.storage-form {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  width: 100%;
  box-sizing: border-box;
}

.storage-form input {
  flex: 1 1 120px;
  min-width: 0;
  max-width: 220px;
  box-sizing: border-box;
}

.storage-form button {
  flex-shrink: 0;
  min-width: 70px;
  max-width: 100px;
  box-sizing: border-box;
}

.storage-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 150px;
  overflow-y: auto;
  width: 100%;
  box-sizing: border-box;
}

.storage-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  transition: background-color 0.3s ease;
  word-break: break-all;
  width: 100%;
  box-sizing: border-box;
}

.storage-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  width: 100%;
  box-sizing: border-box;
}

.storage-info {
  display: flex;
  justify-content: space-between;
  padding: 0.5rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  flex-wrap: wrap;
  gap: 0.5rem;
  width: 100%;
  box-sizing: border-box;
}

@media (max-width: 600px) {
  .storage-form {
    flex-direction: column;
    gap: 0.5rem;
  }
  .storage-form input, .storage-form button {
    max-width: 100%;
    width: 100%;
  }
  .storage-info {
    flex-direction: column;
    gap: 0.5rem;
  }
}

.animated-element {
  width: 100px;
  height: 100px;
  background-color: #4CAF50;
  border-radius: 8px;
  transform-origin: center;
  position: relative;
  will-change: transform, background-color;
}

.demo-card input,
.demo-card textarea,
.demo-card select {
  width: 100%;
  padding: 0.5rem;
  border: 1.5px solid rgba(0, 255, 136, 0.25);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-color, #fff);
  font-size: 1rem;
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
  box-shadow: 0 1px 4px rgba(0,255,136,0.04);
  margin-bottom: 0.25rem;
  box-sizing: border-box;
}
.demo-card input:focus,
.demo-card textarea:focus,
.demo-card select:focus {
  border-color: #00ff88;
  background: rgba(0,255,136,0.08);
  box-shadow: 0 0 0 2px rgba(0,255,136,0.15);
}
.demo-card input[type="color"] {
  padding: 0.1rem;
  min-width: 40px;
  width: 48px;
  height: 38px;
  border-radius: 6px;
  background: transparent;
  border: 1.5px solid rgba(0, 255, 136, 0.25);
}
.demo-card input[type="file"] {
  padding: 0.3rem 0.5rem;
  background: rgba(255,255,255,0.08);
  border-radius: 6px;
  border: 1.5px solid rgba(0, 255, 136, 0.25);
  color: var(--text-color, #fff);
  font-size: 1rem;
  margin-bottom: 0.25rem;
}
.demo-card input[type="file"]::-webkit-file-upload-button {
  background: linear-gradient(45deg, var(--primary-color, #00ff88), var(--secondary-color, #0095ff));
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 0.3rem 1rem;
  cursor: pointer;
  transition: background 0.2s;
}
.demo-card input[type="file"]:focus {
  border-color: #00ff88;
  box-shadow: 0 0 0 2px rgba(0,255,136,0.15);
}
</style>